POSTing to a Single Item vs. Collection (REST API) - rest

Say I have a REST API with endpoint /api/users/. POSTing a user to that endpoint would create a new user and add it to the existing collection, give the user a unique ID so that you can work with it. If I make a GET /api/users/1, this should return me the created user with id: 1. My question is what should be the case for POSTing to a single item instead. For POSTing to a collection, you should return 201 Created if the resource was created, or a 409 Conflict if the resource already exists. What is the best practice for POSTing to a single resource ? Should it return a 405 Method Not Allowed, as you shouldn't be allowed to POST to a single resource or should it return a 404 Not Found as described here ?

If, at the moment a request is received, a resource (regardless of the concept that it represents) does not support a particular method (POST), the correct response to return is 405
The 405 (Method Not Allowed) status code indicates that the method received in the request-line is known by the origin server but not supported by the target resource. The origin server MUST generate an Allow header field in a 405 response containing a list of the target resource's currently supported methods.
The HTTP Specification includes a method (OPTIONS) and response headers (Allow) that enable a client to interrogate a server to discover what methods are permitted. Adoption might be lacking, although I suppose CORS changes that.
Note: there are use cases where POST to a singular resource is a reasonable option (consider how you would define the protocol to star a responsitory in an api where HTML was your hypermedia format). In that case, you should choose the appropriate success code (200, 201, 204...), assuming things went well, of course.

If someone tries to POST to a specific item where it should have call PUT to update. In my opinion 404 should be correct return status code, it tells the client that the resource they are looking is unavailable, which means the URL they are hitting isn't correct.
405 method not allowed should be invoked when client is hitting the right URL with wrong method type. suppose you have /api/users/{id} with PUT, but client is using POST.

Related

REST: which HTTP Status for rejecting method on current state of resource

Imagine the following scenario:
The clients wants to change the state of a resource (e.g Order) via PUT.
The method is allowed for this resource, but the final state change to orderState=payed requires some precondition (like POSTing a valid payment resource to the order).
So PUT is only allowed when the target resource is in a specific state.
What would be a suitable response code?
I think that 405 - Method Not Allowed doesn't really fit to this scenario as it implies that the client can't use PUT at all on that resource.
I'm currently considering 409, 423, 424 and 428 but I'd like to know if there are some best practices regarding this specific scenario.
I would expect 405 Method Not Allowed to cover your case:
The 405 (Method Not Allowed) status code indicates that the method received in the request-line is known by the origin server but not supported by the target resource. The origin server MUST generate an Allow header field in a 405 response containing a list of the target resource's currently supported methods.
My reading is that "currently supported" implies that the list of supported methods may evolve over time.
403 Forbidden is also fine:
The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it.... a request might be forbidden for reasons unrelated to the credentials.
As with any 4xx class status-code, the message-body should include "a representation containing an explanation of the error situation", which is where you insert the explanation of the problem.

What status code to use when a parameter is missing in the query string?

I have an endpoint that requires a parameter passed via the query string (is a GET verb).
What is the appropriated status code to give when this parameter is missing from the request? 400 is the one? or should I respond with a 404?
[GET /search?q=ok] => 200 OK
[GET /search] => 400 Bad Request? or 404 Not Found? Or 422 Unprocessable Entity? Others?
TLDR It's an HTTP 400 - Bad Request.
It's a 400 because the user did not send the Required input field.
why not 422 - because this case fits to 400. Keeping your consumers in mind, you shouldn't go to non-popular response codes if you don't really need to.
Cases for HTTP 404:
Url which the client requested is not existing in your server (usually this will be handled by your server. Application developer usually doesn't have to do anything unless you want a nice looking 404 page or for SEO reasons).
If it was a path parameter and client was looking for an entity with an id (for Example (/students/{id} and your application couldn't find such entity, you may respond with an HTTP 404.
Let's say, user send the query parameter and you did not find any items matching the query param, make no mistake, it's still an HTTP 200 with body as an empty array or so (not a 404 unlike mentioned in the previous case). Example: /customers?lastname=unobtanium
It should be 400 - Bad Request.
The request could not be understood by the server due to malformed
syntax. The client SHOULD NOT repeat the request without
modifications.
404 - Not Found
The HTTP 404 Not Found Error means that the webpage you were trying to
reach could not be found on the server. It is a Client-side Error
which means that either the page has been removed or moved and the URL
was not changed accordingly, or that you typed in the URL incorrectly.
Its means server is not able to find the URI you specified. but in your case URI is valid but parameters are missing so 400 is right way to do it.
What is the appropriated status code to give when this parameter is missing from the request? 400 is the one? or should I respond with a 404?
I would argue that 404 is appropriate
The 404 (Not Found) status code indicates that the origin server did
not find a current representation for the target resource or is not
willing to disclose that one exists.
The fact that your routing implementation happens to send /search and /search?q=ok to the same handler does not mean that they are the same resource. /search identifies a resource, there's no current representation available for it, so you send a response back to the consumer explaining the problem, and put 404 in the meta data.
The big hint in the spec is this one:
A 404 response is cacheable by default
That lets us inform the client (and any intermediary components) know that this response can be reused.
It's a useful property, and it doesn't apply (out of the box) to 400 Bad Request
Heuristic: your web api should act like a document store. If you ask a document store to give you a document, but you spell the key wrong, what do you get? Some flavor of KeyNotFound exception. Same thing you would get if you asked a web server for a document in your home directory, but your spelled the file name incorrectly.
The semantics of the response indicate the right status code to use, not the implementation details.

Use of HTTP 204 vs 200 vs 404 to safely signal that a resource doesn't exist

In my REST API I have the normal CRUD endpoints for some resources.
If I do a GET /items/42 and there is no such item, the normal behaviour would be to return a 404 NOT FOUND.
However, one scenario concerns me. In this scenario, a client needs to check if a resource (which is implicitly idenfitied by a token) exists, and if not, create it. So, the client would try to retrieve the resource, and if a 404 is received the client application would display the UI necessary for creating the item, and then proceed to POSTing the new resource. In a way, this is a special kind of resource, because since its ID is derived from other parameters, it's known even before creation. As an example, consider a user sign-up procedure; the client would ask "Do I exist? If no -> register me".
My concern is really whether I ever need to worry about "spurious" 404:s? Considering a server is usually surrounded by API gateways, reverse proxies and such, is there any risk that a 404 NOT FOUND could be produced by a surrounding entity due to some temporary error not related to the REST server itself? If so, it could trick the client into believing that the item is not created yet, and that it should now be created. Even if the resulting POST request to create the item would fail because the item already exists, this isn't very nice because the user may have entered data etc for no reason.
Is this a problem to take into account or just overly paranoid? I guess if clients can't trust a 404 to be idempotent (until the resource is created, of course), many other issues arise. Is there any actual situation where an API gateway or similar would report a 404 on its own?
If this is a valid scenario, do I need a "safer", more explicit response saying that the request definetely succeeded but the resource wasn't found, such as responding with a 200 OK with an empty JSON body or a {isRegistered: false}, a 204 NO CONTENT, or similar? This opens up for other strange things - if a request for a resource that doesn't exist would respond with a 200 accompanied by an empty body, perhaps creation of the item would be a PUT rather than a POST, etc? This seems like a can of worms... It all boils down to "Does a 404 guarantee that the given resource doesn't exist?".
404 is pretty unambiguous : the resource wasn't found and it's a client error (4xx). Normally, server-side errors (5xx) can't interfere and create spurious 404's here.
As an alternative, if the resource to be created is linked to another resource in a unique way, you could use OPTIONS to ask the server if it already exists.
For instance :
OPTIONS /visitors/7883930/user-account
=> Allow: POST,OPTIONS (doesn't exist)
=> Allow: GET,OPTIONS (exists)
The key here is to have a URI that allows accessing the resource without knowing its ID. It is not always possible though.

How to decide between returning 404 or 405 status on undefined REST routes

I'm writing a RESTful API and I have a doubt. I've created a controller that handles requests to undefined resources (I mean incorrect URIs, not correct URIs but with inexistent IDs).
My first intuition was to return a 404 status code to tell the client the resource doesn't exist (on GET requests), but when I started to generalize the logic to handle HEAD, OPTIONS, POST, PUT and other HTTP verbs, I though that maybe the best idea is to return a 405, since in fact, It's not allowed to use these methods (including the GET) on invalid routes.
In the response for the OPTIONS method I'm returning an empty list of allowed methods (I don't include the OPTIONS method neither, even if it's returning a response).
What do you think? Any ideas? I think this field is a little bit fuzzy.
Just my opinion, but I don't think that's the right way to interpret "Method not allowed", otherwise what would be the point of 404? By the same logic, you could also argue it should be 403 since all users are forbidden from performing the action.
I think this method is about the kinds of operations the service supports for this kind of resource, not any particular instance of a resource. It shouldn't need to even look up the resource (in general), it just needs to look at the URL and method, and decide if that's an available operation.
For example, a write-only resource could return 405 on a DELETE operation.
Probably the most common use of 405 is when a particular URL is valid, but for another HTTP method than was passed in.

Status code to return on not found sub-resource

So let's say I have two resources, Wallet and User. The User and Wallet have a one-to-one relationship. In my REST API, I give the option to give the User a different Wallet, by ID. So a typical HTTP PUT request to move the user to a different wallet could look like this:
PUT /api/user/3 HTTP/1.1
Host: api.myuserandwalletwebsite.com
{
"wallet_id": 15
}
This will update the User to use the wallet with id=15. But, what if the PUT request contains a wallet_id that is not found in the database; what should the REST API then return? Just a simple 404?
Returning a 404 on a sub-resource not found feels weird to me, because the 404 would be misleading: you could think the 404 actually refers to the user not being found.
404 (Not Found) is definitely not the correct response code. The response code you want is 422 (Unprocessable Entity).
The 422 (Unprocessable Entity) status code means the server
understands the content type of the request entity (hence a
415(Unsupported Media Type) status code is inappropriate), and the
syntax of the request entity is correct (thus a 400 (Bad Request)
status code is inappropriate) but was unable to process the contained
instructions.
    -- RFC 4918
It is a well-understood and well-defined response code, and can be found in the Hypertext Transfer Protocol (HTTP) Status Code Registry maintained by IANA.
As a side note, you're not using HTTP PUT according to the spec. A PUT should update the entire contents of the resource in an idempotent manner. You should be using either PATCH or POST.
As an alternative, you might consider a joining resource, such as a /user-wallet endpoint. That may or may not make sense depending on the specifics of your API.
Like you already mentioned: I would also not use 404, because it would mean the user could not be found. As you want to update your User resource and this update fails due to invalid data (a reference to an invalid Wallet) I would rather use 400 Bad Request and add a meaningful message to an additional header field (e.g. X-Message: Wallet with ID 15 not found).
HTTP 422 Unprocessable Entity is also a good idea, but not covered in RFC2616. If this "extension" is no problem you can go with this one.
HTTP 405 is not correct here as this would mean the PUT method is generally not allowed on the users resource and that PUT would not be included when firing OPTIONS to the resource which is not the case.
In my application that using REST-API I trying to follow best-practises described here: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
And I know many programmers from GOOD Software development companies that also take care about this.
So as was described in best-practises in case of not found resources just simple use:
404 Not Found - When a non-existent resource is requested
That is first case - common best practises.
Second: thing behind best REST-API practisies is Your application logic:
I think You have some options based on Your app-logic :
404 Not Found - When a non-existent resource is requested because You requested non-existing wallet
405 Method Not Allowed - You cant put because wallet not found and it is required for update
422 Unprocessable Entity - Used for validation errors because we have validation in our app that check for incomming requests
So concrete status is only Your decision. Remember the option that You choose will propagate for rest of Your logic application so be consistent and consider the REST-API like GUI dedicated for other application