I am designing a RESTful API that is managing favorites. Each favorite resource can contain details of two items that are considered as part of the favorite.
HTTP POST /favorites
{ "item1" : "ball",
"item1-ID" : "1",
"item2" : "bat",
"item2-ID" : "2"
}
Please excuse the rudimentary JSON payload. The focus is however on the semantics of the POST
The above POST method creates a new favorite resource (that contains a ball (ID 1) and a bat (ID 2))
My question is with regard to the expected behavior when the same POST request is sent twice. The first request will create a favorite (as expected). What should happen when the second request is sent?
1) Signal an error with 409
2) Signal a success with 201
1) is not idempotent (as POST is), while 2) makes POST idempotent.
Which is the correct approach?
You are thinking about this in the wrong way. If a POST
creates a new resource then the resource should have a URL that identifies it (e.g., http://.../favorite/1
). When the second POST
with the same payload happens, is a new resource created? If so, then you have two separate resources with unique URLs. If you application does not create a new resource, then the second POST
would return the same URL as the first one.
Edit
The POST
section of RFC7231 does not prohibit it from being implemented in an idempotent manner. It does provide some guidance though:
POST
creates a new resource, then it SHOULD send a 201 (Created) response containing a Location header identifying the created resourcePOST
is equivalent to an existing resource, then the server MAY redirect the UA to the existing resource by returning a 303 (See Other) with the appropriate Location headerPOST
is not required to change the state of a resource. However, GET
and HEAD
are required to be idempotent. I'm not aware of any method that is required to change state on the server.
Personally, I implement resource creating POST
methods as returning a 303 redirect to the canonical URL for the resource as a matter of practice. I wasn't aware of the RFC distinguishing status codes for resource creation and re-use responses. The benefit of this approach is that it removes the need to include the created resource in the POST
response and the GET
to the canonical URL will cache the response in any intermediate caches that may be present. It also allows for the implementation of intelligent clients that do not retrieve the response and use the canonical URL (from the Location header) instead.
In your case, I think that I would adopt the 303 approach provided that a favorite has a URL of it's own; 201 would be strange if it did not. If there is very good reason for distinguishing the creation and re-use cases in the response, then a 201 when the new resource is created and a 303 when it is reused is appropriate. What I would not do is to return a 409 unless your application requires you to deny the creation of a resource that already exists.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With