-2

I am trying to design a RESTful web API for mostly CRUD operations.

I have a design dilemma on how to model a save action for an entity which also can have optional side effects like updating other "child" entities that were not part of the original entity.

Example:

  • Template Entity
  • Child documents Entity

Template can have multiple child documents If a template is updated, all or some of the children based on the entity can be updated.

GET /templates/{id} -> Returns template
POST /templates/ -> Creates template
PUT /templates/ -> Updates template

Now if we want to update template and also instruct the server to update all documents based on the template, what would be a good design?

1)

PUT /templates/ 
{
  template: {
    ..
  },
  childDocumentsIds: [1, 3, 7...]
}

2)

PUT /templates?childDocumentIds=1,3,7
{
template
}

Similar questions has already been asked, but they do not quite answer my question:

I am trying to judge if other people have similar questions when designing REST APIs. Also lately after experience with few of them, I think we can do better than REST APIs.

peceps
  • 17,370
  • 11
  • 72
  • 79

1 Answers1

1

I think we can do better than REST APIs.

The REST architectural constraints are designed with a particular problem in mind: "long-lived network-based applications that span multiple organizations." The reference application for REST is the world wide web. If that's not the kind of problem you have, then REST may not be the right fit.

HTTP is an application, whose application domain is the transfer of documents over a network. If you can frame your problem as document transfer over a network, then a whole bunch of the work has already been done for you, and you can leverage it if you are willing to conform to its constraints.

The remote authoring idioms in HTTP (primarily GET/PUT) are very crud like - please give me your latest representation of some document; here is my latest representation of some document, please make your copy look like mine. Our API is a facade -- we pretend to be a dumb document store that understands GET and PUT semantics, but behind the scenes we do useful work.

So we might have, for example, a simple todo list. At the beginning, it is empty

GET /todoList

200 OK

[]

And if we wanted to send an email to Bob, we would first edit our local copy of the document.

["Send an email to bob@example.org"]

And then we would ask the server to make its copy of the document look like our copy

PUT /todoList

["Send an email to bob@example.org"]

HTTP semantics tell the server how to interpret this message, but it gets to choose for itself what to do with it. The server might, for example, update it's own local copy of /todoList, send the email to Bob, update its representation of /recentlySentEmail, update its representation of /recentlySentEmailsToBob, and so on.

The response from the server takes a number of standard forms; 202 Accepted -- I understood your request, and I may do it later; 204 -- No Content -- I edited my copy of the document to match yours, here's some meta data; 200 OK -- I've made changes to my representation of the document, here they are (or alternatively, I've made changes to my copy of the document, you can ask me for a refreshed copy).

if we want to update template and also instruct the server to update all documents based on the template, what would be a good design?

The most straight forward example would be to just send the revised template, and allow the server to update other resources as it sees fit

GET /template

200 ....
[original representation of template]

// make edits

PUT /template
[revised representation of template]

200 OK

If the server knows which documents need to be updated, it can just update them. Ta-Da.

If the client needs to know which resources have been updated, just send that list back

PUT /template
[revised representation of template]

200 OK

[URI of resources changed by the template]

It can be a useful design exercise to work through how you might achieve the result using a web site. How might it go. You would GET a resource that includes a form; the form might include a text area with some string representation of a template. You would replace the representation in the form with the one you wanted, and submit the form, carrying the template to the server. It would make changes, then give you back a new form, with check boxes for the different resources that will be affected by the change, allowing you to perhaps change the default selections. You would submit that form, and then the server could make the appropriate changes.

That, right there, is REST -- because you are using standardized media types, general purpose components (like browsers) can do all of the HTTP and HTML book keeping. The browser knows how forms work, it knows how to take the form processing rules and meta data to create the appropriate requests. The web caches all know which representations can be stored, and which should be invalidated.

VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
  • Thanks for taking the time to answer this. I understand it fully. I have designed many REST APIs used in production systems for many years by many users. Also implemented clients as Android Apps, JS frontends. The frustration comes from even after years of designing REST APIs I still have dillemas on how to model requests. And I am not the only one. "I think we can do better" was meant in more in the direction of more rules over REST design, or more in the direction of leveraging REST into something more generic (like GraphQL). With this question I wanted to gauge who else shares my pain. – peceps Nov 20 '19 at 12:35
  • Come to think of it, Stack Overflow was probably not the right place to post this. I will most likely delete the question. – peceps Nov 20 '19 at 12:37
  • Yes, there is a big gap in the "I want to have a conversation about...." space. – VoiceOfUnreason Nov 20 '19 at 12:54