2

I have the resource OrderRequest which I guess can be qualified as process. The OrderRequest can be create of update. The create should be idempotent, because creating the same order request 2 times is undesired. At the same time the POST is not idempotent and it does not always return the same result. I use a combination of Client side generated Id and server side generated Id. When create is executed the client side generated Id is used so it ends up as

PUT /orders/clientGeneratedID

It will return also a server generated Id that can be used. There is a subtle difference between the two Ids because having clientGeneratedtID means also that there is a "dealer order" associated with the order.

Once created a modification is modified via clientGeneratedID or server generated Id.

POST /orders/{clientGeneratedID or serverGeneratedID}/modifications

Reading through various posts I understand there is some confusion about POST and PUT with regards of what is create and what is UPDATE.

My understanding is that since I supply the Id and the URL the correct verb for my create is PUT. At the same time since I am creating a process it does not sound correct for me that PUT should be also update I am not entirely replacing the resource which is a prerequisite for using PUT for update. So I have decided to use POST.

Is it wrong that I have both PUT and POST in such way? Am I doing it right? I understand that I can do an idempotent POST for create. But is there a general guideline that you should use either PUT or POST but don't combine and what about the fact that I use them in reverse PUT for create and POST for update?

  • Does the design of your software require strict adherence to REST principles as described by Roy Fielding's thesis? Most applications do not. Note that, to be fully REST compliant you must also implement HATEOAS; is it your intention to do so? – Robert Harvey Feb 18 at 17:49
  • PUT and POST doesn't have any correspondence with CRUD. – Lie Ryan Feb 18 at 17:51
  • @RobertHarvey No it does not, Actualy we have taken the decision to implement up to Level 2. Level 3 is not in the picture. – Alexandar Petrov Feb 18 at 18:30
  • @LieRyan That I understood kind of, but it seams as that majority of developers are thinking either Post - create / Post - update or Post - Create / Put - update. I have never actualy seen reverse PUT for create where it should be idenpotent and post for modifications. – Alexandar Petrov Feb 18 at 18:32
  • How about PATCH for update? – slepic Feb 18 at 18:37
2

I'm mostly with you on the PUT design. The client does a PUT to a specific Id that they specify. If the resource doesn't exist, you create it and return a 201 response code. The question is what happens if someone attempts to PUT to that same resource again. The standard PUT semantics would be to overwrite whatever is there with the new content provided but I think you want to disallow this and that's fine. You can return an error (400 should work) with some detail that the resource cannot be replaced.

As an aside, the point of PUT idempotency is so that if you encounter an error in processing a PUT, you can repeat the call without fear of corrupting things. This means (in theory) that a client library can call PUT in a loop until it succeeds. It can't do that with POST because each call might be creating distinct resources. So, if you want to get really fancy and the content is the same as what is already there, you can return 200 OK and only return an error if something is trying to replace the order with something different.

Then we get to the POST operation: "I am not entirely replacing the resource which is a prerequisite for using PUT for update. So I have decided to use POST."

You have some options here. One is to introduce the PATCH verb. This verb is meant to allow for partial modifications to a resource. Personally, I think that unless you really understand why this is a good choice for your design, you should avoid it as it means you more-or-less need a mini-language to specify the transformations you are making.

I think POST makes sense here if I am following. The intention of POST essentially attempts to create a new resource. In this case, the new resource is a 'modification' to the order. This is pretty standard in business. Modifications to orders are treated as their own transaction. The history of the original order and all the modifications are all important information. If you are worried about doing this 'the right way' you should be assigning a new URI for each successful modification e.g.: /orders/bub123/modifications/001.

But is there a general guideline that you should use either PUT or POST but don't combine and what about the fact that I use them in reverse PUT for create and POST for update?

You can combine PUT and POST in a number of different ways. There's absolutely no rule saying you have to choose. It's just the semantics are different. To give a perhaps useful example, it might make sense to support POST against /orders/. The distinction would be that in this case you wouldn't assigning it a client specified id. The server would create a new id e.g. 98765 and return the corresponding URI /orders/98765. If you want to allow replacement, that URI then could accept a PUT call.

POST is not for update and I would argue that it's not being used for update here. I understand your line of thinking because, in the general sense, it is an update of the order. But in the REST sense, your design here is actually creating a child resource of the order, the original order content remains intact but now has a modification attached to it. I think it's a pretty sensible design and that it's just the nomenclature that's tripping you up.

| improve this answer | |
  • My example may be wrong here , but the relationship is One To One. For one specific order you can have only a single client no matter how strange it is :) Better example is Dealer Order - Factory Order for one dealer order you can have only one factory order. – Alexandar Petrov Feb 18 at 18:35
  • Also forget the clientID I just used it as a way to say that clientGeneratedId is a key generated at the client and has nothing to do with the Client entity ID. – Alexandar Petrov Feb 18 at 18:36
  • please read again the question. It is updated. – Alexandar Petrov Feb 18 at 18:40
  • modifications are not idempotent,. But the create is, I can create order only once and then just return "already created" – Alexandar Petrov Feb 18 at 18:46
  • I've added updates based on yours. – JimmyJames Feb 18 at 19:54
1

I would avoid the ambiguous semantics of having both a resource identifier of clientGeneratedID and serverGeneratedID. I would make for cleaner semantics if the client generated ID was in the request / object body.

Then you can move on to POST semantics where a POST either succeeds and returns a serverGeneratedID (usually in the location header), or it does not. I am assuming you are creating something on the server, and the clientGeneratedID is something the client wishes the server to preserve, but the server does not need to understand clientGeneratedID and has no previous data referred to by clientGeneratedID.

You can check for the existence of other objects with the same clientGeneratedID and return 409 Conflict if a, err, conflict exists.

REST doesn't have a clear answer for a lot of use cases. I would recommend to make the best decision you can and move on. Just keep it consistent within the API (or group of APIs if you can). I have a list of 20-ish regulations for my group for items that are not specified or ambiguous in REST. For example API versioning.

| improve this answer | |

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.