-1

I'm looking for the "Holy Grail" (best practise) of how to update an entity with REST?

There are three main approaches I've found so far:

  • Always send full entity, regardless what has been changed and just overwrite the previously stored data. (This is the one I'm using right now, but it's ugly because of hidden fields and stuff on UI)

  • Send partial data (e.g. settings from one tab on the UI) - in my opinion this one somewhat couples the API to the client side, because I have to create DTOs for each view, if I don't, I cannot determine if something is null/empty because the user deleted that form's value or just not sent by the client.

  • Create update methods for every value that can be modified - this would be the least error-prone but a nightmare to implement and maintain.

Are there any other methodologies I could use? (I'm using Java + Spring by the way, if there is a solution which solves this I'm happy to integrate.)

  • 3
    Sorry to disappoint you, but there is no singular "best practice". Just multiple ways to do the task with various pros and cons, where a pro in one situation might be a con in another. – Bart van Ingen Schenau Sep 9 '18 at 8:51
  • @BartvanIngenSchenau that was my fear. :) I'm still hoping that someone has a secret one, or a trick that eases it. – Peter Sep 9 '18 at 9:01
0

As @Bart said in comments, there is no holy grail for this because different requirements drive different choices and optimization’s.

That said, I think you have presented a few assumptions that I’d like to challenge your thinking on to help you through the decision process. I’ll go through each with HTTP verbs and URLs to be clear.

PUT /api/thing. {full object} This is usually the default starting point for most APIs. For most APIs this works quite well, even with large objects, because the client fetches first the original resource with a GET and then PUTs the whole updated object back. The client can normally just worry about updating changes in memory and this keeps things clean.

The main downside here is actually in concurrency, IMO, as your serverside logic becomes trickier if you want to track granular changes (eg userA pulled v1 of the document and modified field1 while UserB pulled v1 and modified field 2. ). It’s certainly doable to merge those changes, but normal out-of-the-box logic in most frameworks will usually be to reject the second of the writes or overwrite the first, so it’s on you to do a meaningful merge if you want that.

PATCH /api/thing {partial} I somewhat disagree with your statement that you have to do different DTOs here. Yes, you need to differentiate deleted vs unchanged fields, but you can do that by having the client explicitly send a flag to set a field to a meaningful null, if a given field can be null or blank. Unchanged fields should not be sent at all, so your DTO parsing on the server has to be smart enough to do that of course. It’s also important to note that validation should be performed on the modified resource/ entity, as DTO-Level validation is of limited use (it’ll only catch naive problems like bad format or nulls, not the more complex interactions between fields)

Finally, I think there’s a granularity option you hinted at wanting but didn’t include (I’ll skip your third option because I agree it’s rarely the right choice)

PUT /api/settings/profile In this approach, you make each tab of your settings pane an atomic change, rather than either each field or the whole settings resource. In many ways this is the most “tunable” approach, while sharing some of the pros and cons of the other two.

  • Thank you @Paul for the clarification, you made me think. I guess I'll stay with the full object path. – Peter Sep 9 '18 at 13:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.