Since rest deals with documents I'm not sure how those would translate into operations executed on a domain model, given that documents are anemic and domain models are not.
A principal coisa a ter em mente é que o ponto de uma API da web é adaptar seu domínio para a web; isto é, para fornecer a ilusão de que seus recursos são realmente apenas entradas em um armazenamento de documentos.
De certa forma, um consumidor deve ser capaz de conduzir sua API usando um editor de documentos com conhecimento da web.
Abordagem de granulação grossa
The save action will result in a PUT request (PUT /orders/3) containing the entire order including order lines. The drawback is that it's hard to figure out what has changed (i.e. which order lines should be added / updated / deleted?).
Essa é uma abordagem perfeitamente razoável: você diz à API como deseja que o recurso seja exibido e a API precisa descobrir como chegar lá.
Como os carrinhos de compras geralmente não exigem colaboração entre vários editores, você pode obter criando um novo modelo de dados para o recurso a partir do instantâneo que recebeu e, em seguida, substituindo o modelo existente.
Se você, por qualquer motivo, precisar descobrir mais mensagens de comando de granulação do diff; sim, isso pode ser estranho. Em um caso como este, não é tão ruim - você pode detectar mudanças com bastante facilidade, e qualquer mudança válida provavelmente é tirada de um pequeno vocabulário.
Também é importante notar que você não precisa suportar PUT em qualquer representação arbitrária do recurso, mas pode escolher uma representação que faça sentido (e, esperançosamente, uma onde é fácil identificar as mudanças corretas ).
Abordagem refinada
The delete order line action will result in a DELETE request (DELETE /orders/3/lines/5).
Qualquer URI que você queira usar é bom no que diz respeito ao REST; mas conceitualmente pode ser melhor pensar em termos de remover a entidade por id, em vez de por posição na lista.
The add order line action will result in a POST request
Também pode ser feito como um PUT.
This implies the app now needs to keep track of a lot of changes, and execute the changes in the correct order when the user decides to save.
Sim; Acredito que você tenha uma situação semelhante com um cliente ocasionalmente conectado. As mensagens de comando são enfileiradas até o sistema de destino ficar disponível.
Outra abordagem a considerar seria manipular o histórico do recurso, em vez do próprio recurso. Efetivamente, a história se torna uma coleção única de alterações.
I'm just wondering how I can avoid duplicating business rules on the client. For example, if an order line cannot be deleted under certain circumstances, nothing prevents the client from doing so.
Há algumas respostas aqui, com base na ideia de que você sinaliza essas informações nas representações.
Uma resposta é que você simplesmente anota que a linha do pedido não deve ser excluída. As regras de negócios que decidem se uma linha de pedido pode ser excluída ao vivo no servidor, o cliente apenas vê que o sinalizador foi definido.
Você pode comunicar essas informações fora da banda para os clientes.
Na abordagem refinada, a resposta usual é que você usa controles hipermídia. Em vez de os clientes enviarem uma mensagem para um terminal pré-determinado, espera-se que o cliente examine a representação e "siga um link". Assim, você pode comunicar o fato de que um item de pedido não pode ser excluído, removendo o link do item de exclusão da representação.
Em uma abordagem específica, suponho que você poderia tentar distinguir as partes modificáveis do recurso e fornecer representações editáveis apenas das partes que o cliente pode editar. Há uma certa confusão lá.