I'm building a server that allows clients to store objects. Those objects are fully constructed at client side, complete with object IDs that are permanent for the whole lifetime of the object.
I have defined the API so that clients can create or modify objects using PUT:
PUT /objects/{id} HTTP/1.1
...
{json representation of the object}
The {id} is the object ID, so it is part of the Request-URI.
Now, I'm also considering allowing clients to create the object using POST:
POST /objects/ HTTP/1.1
...
{json representation of the object, including ID}
Since POST is meant as "append" operation, I'm not sure what to do in case the object is already there. Should I treat the request as modification request or should I return some error code (which)?
I don't think you should do this.
The POST is, as you know, to modify the collection and it's used to CREATE a new item. So, if you send the id (I think it's not a good idea), you should modify the collection, i.e., modify the item, but it's confusing.
Use it to add an item, without id. It's the best practice.
If you want to capture an UNIQUE constraint (not the id) you can response 409, as you can do in PUT requests. But not the ID.
Personally I go with the WebDAV extension
422 Unprocessable Entity
.REST Patterns describes it as
What about returning a 418?
Because the client ask to persist an entity that already exists on the server, the server finally gets mad and think he's a teapot and return:
418 I'm a teapot
.References:
I think for REST, you just have to make a decision on the behavior for that particular system in which case, I think the "right" answer would be one of a couple answers given here. If you want the request to stop and behave as if the client made a mistake that it needs to fix before continuing, then use 409. If the conflict really isn't that important and want to keep the request going, then respond by redirecting the client to the entity that was found. I think proper REST APIs should be redirecting (or at least providing the location header) to the GET endpoint for that resource following a POST anyway, so this behavior would give a consistent experience.
EDIT: It's also worth noting that you should consider a PUT since you're providing the ID. Then the behavior is simple: "I don't care what's there right now, put this thing there." Meaning, if nothing is there, it'll be created; if something is there it'll be replaced. I think a POST is more appropriate when the server manages that ID. Separating the two concepts basically tells you how to deal with it (i.e. PUT is idempotent so it should always work so long as the payload validates, POST always creates, so if there is a collision of IDs, then a 409 would describe that conflict).
According to RFC 7231, a 303 See Other MAY be used If the result of processing a POST would be equivalent to a representation of an existing resource.
Late to the game maybe but I stumbled upon this semantics issue while trying to make a REST API.
To expand a little on Wrikken's answer, I think you could use either
409 Conflict
or403 Forbidden
depending on the situation - in short, use a 403 error when the user can do absolutely nothing to resolve the conflict and complete the request (e.g. they can't send aDELETE
request to explicitly remove the resource), or use 409 if something could possibly be done.Nowadays, someone says "403" and a permissions or authentication issue comes to mind, but the spec says that it's basically the server telling the client that it's not going to do it, don't ask it again, and here's why the client shouldn't.
As for
PUT
vs.POST
...POST
should be used to create a new instance of a resource when the user has no means to or shouldn't create an identifier for the resource.PUT
is used when the resource's identity is known.