The URL is an opaque value by definition, meaning that it does not necessarily reflect the structure of your application; so much so that accessing /user/1
is not necessarily access the file in /user/1/index.html
, the URL may not represent the folder organization (or it may, as is common for static files).
That said, the final answer to your question is: it depends on the requirements of your application.
We cannot say what is right or wrong, because in one application it can make sense and in others it cannot. Being the URL opaque, in different applications it can represent different resources and thus require different responses.
Let’s start with the counterargument of your question: we have an application where I can access a user’s information both with /user/1
how much /user/anderson-carlos-woss
. It turns out that in the first case I informed the user ID, while in the second I informed the name. In my application I guarantee that both will be unique for each user. IE, access the resource /user/null
, for example, it would make my application reach the correct resource (users), there would probably be a condition that would check if the value is a number; if it is, search for the id, otherwise search for the name. In this case, the user with the name Null would be searched from the bank and if not found would generate an error response.
Do you realize that in this case the feature of the application was identified correctly, the whole search was done and did not find the record in the bank? For this situation the indicated response would be the 404 Not Found, because its application managed to process the request successfully, only did not find the resource that the client requested.
In your question you quote:
... id passes a regular expression validation of type [0-9]+
And that’s what defines which one to use. Your application requirements require that the id provided by the URL must be a non-negative integer value. If the customer requests the resource /user/null
, it is more interesting you inform him that the request is wrong and that he needs to fix it before trying again. See, it’s a problem in the request, not in the application. Errors in the request are reported with the 400 Bad Request response, which basically tells the client "man, your request makes no sense, I don’t know what to do with it".
In short:
- Reply with 404 Not Found when the route exists in that format, but the resource in question was not found;
- Reply with 400 Bad Request when there is no route in that format;
So is it wrong for me to send the 404 answer in this case? No! It depends on your application. Some applications choose to send the 404 response even if the request is wrong to hide the structure of the application itself. Let’s say a user with bad intentions tries to hack the resource /user/null
and receives the answer 400 he will know that the request is wrong and will try to make the attack on a similar resource until he gets another answer; while if he gets the answer 404 he may find that the appeal does not exist and give up the attack. It depends on what resource we are dealing with, what context it will be used for and what the application requirements are.
My view is quite simple: the application should be protected against attacks on any resource, it is not an HTTP response that will change that, so I always try to use the one that makes it easier for the client (well-intentioned).
And in the case of instead of a parameter in the invalid URL, a parameter in the body, for example, a route that needs two parameters, oldPassword
and newPassword
, but the requisition only has newPassword
?
Same situation. Will your application know what to do when you only have one of the values? If yes, the request is valid. If not, the application has nothing to do with the request, then respond with 400 Bad Request.
Remember that it is not rude to tell the client that he is wrong. If he made a wrong request, let him know so that he can correct.
Another way to analyze the problem is by checking the definitions of each answer:
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.
Translating, the request may not have been understood by the server due to the badly formatted syntax. The client MUST NOT repeat the request without modifications.
That is, if I access the resource today /user/null
and get the answer 400, I’ll know that at all times that I make this same request I will have the same answer. If there is a possibility that tomorrow (or another time) the resource exists, then the answer should be 404, not 400. Ah, but what if one day I want to create this feature, then should I already use the 404 answer? No. You answer as your application is today. The day you create the new feature you change the answer.
404 Not Found
The server has not found Anything matching the Request-URI. No Indication is Given of whether the condition is Temporary or Permanent. The 410 (Gone) status code SHOULD be used if the server Knows, through some internally configurable Mechanism, that an old Resource is permanently unavailable and has no Forwarding address. This status code is commonly used when the server does not Wish to Reveal Exactly Why the request has been refused, or when no other Response is applicable.
Translating, the server did not find results for the requested URI. No indication is given as to whether the condition is temporary or permanent. The 410 (Gone) response should be used if the server knows somehow that the resource existed and was permanently removed without any alternative address. This response is commonly used when the server does not wish to reveal the actual reason for the request to be refused.
In this case, reply with 404 when accessing /user/null
does not mean that one day this resource will exist. It merely indicates that today it does not exist and that there is the possibility of existing one day. If the feature existed and was deleted, the application can respond with 410 (this is common in applications that perform the soft-delete).
Also as previously commented, the 404 answer is more generic and can be used on different occasions, either to avoid revealing information about the application or because there were no better answers to the situation.
Another question that is quite common is how to differentiate if the route does not exist or if the record does not exist when receiving the answer 404. If I access /user/1
and I get the answer 404 means I should try another route, like /usuario/1
, or my route is right and is id 1 that does not exist in the bank?
To make this differentiation it is common to use the body of the reply sending a message with details about why it was generated.
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
{"error": "Rota não encontrada"}
Or
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
{"error": "Usuário 1 não encontrado"}
You can even change the description of the answer (Sponse) freely, but it is not so much dependent on it to indicate the error, for it is much easier to work with the body of the answer than its description. If the client is something more visual to the user, like Postman, it might be interesting to use it:
HTTP/1.1 404 User Not Found
Content-Type: application/json; charset=utf-8
{"error": "Usuário 1 não encontrado"}
This can make it easier for the user as it does not require them to analyze a possible JSON in the body of the response.
If the request is wrong/incomplete, 400. "Bad Request" is just to answer a "look, the error was on your side, not on the server. Turns to correct".
– Woss
@Andersoncarloswoss then both cases I cited would be incorrect return 404?
– Costamilam
In my understanding, yes. The route exists and has been found, it makes no sense to answer with 404.
– Woss