So i have one single http post
API called UpsertPerson, where it does two things:
check if Person existed in DB, if it does, update the person , then return Http code 200
if not existed in DB, create the Person, then return http 201.
So is it a good practices by having the same api return different statusCode (200,201) based on different actions(update, create)?
This is what my company does currently , i just feel like its weird. i think we should have two individual api to handle the update and create.
CodePudding user response:
ninja edit my answer doesn't make as much sense because I misread the question, I thought OP used PUT
not POST
.
Original answer
Yes, this is an excellent practice, The best method for creating new resources is PUT
, because it's idempotent and has a very specific meaning (create/replace the resource at the target URI).
The reason many people use POST
for creation is for 1 specific reason: In many cases the client cannot determine the target URI of the new resource. The standard example for this is if there's auto-incrementing database ids in the URL. PUT just doesn't really work for that.
So PUT
should probably be your default for creation, and POST
if the client doesn't control the namespace. In practice most APIs fall in the second category.
And returning 201/200/204 depending on if a resource was created or updated is also an excellent idea.
Revision
I think having a way to 'upsert' an item without knowing the URI can be a useful optimization. I think the general design I use for building APIs is that the standard plumbing should be in place (CRUD, 1 resource per item).
But if the situation demands optimizations, I typically layer those on top of these standards. I wouldn't avoid optimizations, but adopt them on an as-needed basis. It's still nice to know if every resource has a URI, and I have a URI I can just call PUT
on it.
But a POST request that either creates or updates something that already exists based on its own body should:
- Return
201 Created
and aLocation
header if something new was created. - I would probably return
200 OK
The full resource body of what was updated aContent-Location
header of the existing resource if something was updated. - Alternatively this post endpoint could also return
303 See Other
and aLocation
header pointing to the updated resource. - Alternatively I also like at the very least sending a
Link: </updated-resource>; rel="invalidates"
header to give a hint to the client that if they had a cache of the resource, that cache is now invalid.
CodePudding user response:
So is it a good practices by having the same api return different statusCode (200,201) based on different actions(update, create)?
Yes, if... the key thing to keep in mind is that HTTP status codes are metadata of the transfer-of-documents-over-a-network domain. So it is appropriate to return a 201 when the result of processing a POST request include the creation of new resources on the web server, because that's what the current HTTP standard says that you should do (see RFC 9110).
i think we should have two individual api to handle the update and create.
"It depends". HTTP really wants you to send request that change documents to the documents that are changed (see RFC 9111). A way to think about it is that your HTTP request handlers are really just a facade that is supposed to make your service look like a general purpose document store (aka a web site).
Using the same resource identifier whether saving a new document or saving a revised document is a pretty normal thing to do.
It's absolutely what you would want to be doing with PUT semantics and an anemic document store.
POST can be a little bit weird, because the target URI for the request is not necessarily the same as the URI for the document that will be created (ie, in resource models where the server, rather than the client, is responsible for choosing the resource identifier). A common example would be to store new documents by sending a request to a collection
resource, that updates itself and selects an identifier for the new item
resource that you are creating.
(Note: sending requests that update an item to the collection is a weird choice.)