I have a REST request (Not completely REST though). The input data is received via HTTP payload as XML and thus the record to be read is specified in the xml as,
<Item>
<ID>1</ID>
</Item>
Here, if the ID '1' is not found in database, should I return 404 Not found.
According to https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html, 404 Not Found is referred as The server has not found anything matching the Request-URI. But in my case, the URI can be reached successfully and the data in payload could not be found. Is it appropriate to use 404 or should I use any other status code?
First of all, why are you sending a payload to retrieve data? If you want to retrieve data in a RESTful way, you should send the id in the path, like /some-resource/1. I hope there is a very good reason to don't follow that standard.
In any case, returning a 404 is the best approach, in my opinion. Any client would expect a 404 if the resource was not found, even when the formal definition specifies that the resource is in the URL.
Related
We had a bit of a heated debate at work this week regarding the proper use of HTTP error code 404. I feel that it is being used inappropriately in this situation, and they insist that "this is how it is everywhere".
Here's the scenario:
We have a REST API endpoint with a static URI like "https://server.domain.com/restapi/getnode" that accepts a json body during a POST operation to see if a server exists within the database. There is 1 server allowed per query.
The way it is designed, if the server exists, it returns http code 200 with the body of the message being the details of the server within the database. If it doesn't exist, then they return a 404 code with the message "server x is not found in database y".
I feel that this is incorrect because according to the standards from W3C 4xx codes are for client-related issues, and 404 is specifically if the server can not server up that specific URI. Further, this is not really an error, we would not only expect the occasional negative/empty response as part of the normal business, but that is expected to be the state on the majority of the calls.
Their response to this is that according to sources such as AWS REST Standards and ServiceNow REST Standards that 404 is appropriate because the query didn't find the server, therefore it couldn't find the resource (To which I feel that they are misinterpreting the term "resource").
So, who is correct here? Or is this more of a gray area than I think it is?
The relevant part of the specification here is Client Error 4xx.
Except when responding to a HEAD request, the server SHOULD send a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition.
User agents SHOULD display any included representation to the user.
In other words, the status code is meta data that indicates to general-purpose components that the payload of the response is an explanation of the error, and not a representation of the resource.
If what you are actually doing is returning a representation of the resource which is at this moment an empty list, then you should be using a Successful code, not a Client Error code.
For example, if we have a resource that lists women who have been sworn into the office of President of the United States, the expression of that resource, as of 2019-09-25, would be an empty list. So a standard HTTP response would look like
200 OK
Content-Type: application/json
[]
On the other hand, this response says something completely different
404 Not Found
Content-Type: application/json
[]
What this says is that there was no current representation of the requested resource, and the representation of the explanation of the problem is an empty list, so please show an empty list to the user so that they know what to do.
This is a neverending debate with no useful outcome. See for example How to design RESTful search/filtering?, Do web applications use HTTP as a transport layer, or do they count as an integral part of the HTTP server? (disclaimer: my question), and thousands of other questions on the Stack Exchange network and thousands of blogs like "which status code to pick for REST scenario XYZ".
The fact that you're using POST for a request with GET semantics, means you're already not properly applying REST. POST is used to create resources, not to find existing resources. If you have a "servers" resource collection, then you're dealing with "server" resources.
If you want to have a "find-server" endpoint, and you want to use POST to "create" a "find-server resource result", which you can then issue a GET request to to obtain your search results, you're a masochist who tries to shoehorn an application into a design philosophy that doesn't fit the problem domain.
So just be pragmatic. Does the endpoint exist? Yes, so 404 is not applicable. Return a 200 (the resource exists, the request is correct) with an body indicating no results were found, or a 204 ("no content") without a body.
We are using a specific endpoint on our API to test if an e-mail address is already registered in our database. When it's not, what would be the right status code to return to the client ?
We cannot take a decision between 404, 204 and 200. There are a couple of articles over the net but all state pros and cons but it's not very clear.
200 says that the request was successful
204 says that the request was successful AND that the message body included in the response is 0 bytes long.
404 says that there is no current implementation associated with the requested resource
Which of these is correct really depends on your resource design.
Consider a database query with a where clause -- if there are no matching rows, then you get SUCCESS, with an empty result set. So the analogous thing in a HTTP response would be a 2xx status code, and a body that describes an empty set.
If you were using a JSON List as your representation of the set, then the representation would be two bytes long [], and a 200 status code would be appropriate. If you were using a json lines representation, with each record on its own line, then with no records you would have no lines, therefore a 0 byte representation and 204 would be a good choice.
What about a case where we have a simple web page, that tells you if the email address is registered or not? If it's registered, the server responds with a 200 message and a html document that tells you about the registration. If it isn't registered, then you get an html message telling you that the email address isn't registered... and a 200, because we were able to find the current representation of the resource.
And 404? 404 indicates to the client that there appears to have been a spelling error in the target-uri of the http request -- that there isn't even nothing to find.
It may help to understand that status codes are metadata about the HTTP response, which is to say that they are part of the application domain of transferring documents over a network, not about the business domain. They are there so that generic components, like caches, can do interesting things without needing to know any specifics about the domain in question.
Our web API is a facade to make our domain model look like a boring document store.
Lets suppose that someone performs a PUT request on my endoint:
/resources/{id}
However there is not resource with the given id stored in my PostgreSQL database.
According to the RFC 2616, I should create the resource if I am capable to:
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
Would be okay to create the resource with the provided id? As manually assigning ids on database insert is not the best practice.
Should I return a 404 error if the creation of the resource is not possible?
First of all, you are using an obsolete document: The RFC 2616 is no longer relevant nowadays and anyone using such document as reference should stop right away.
Quoting Mark Nottingham who, at the time of writing, co-chairs the IETF HTTP and QUIC Working Groups:
Don’t use RFC2616. Delete it from your hard drives, bookmarks, and burn (or responsibly recycle) any copies that are printed out.
The old RFC 2616 has been supplanted by the following documents that, together, define the HTTP/1.1 protocol:
RFC 7230: Message Syntax and Routing
RFC 7231: Semantics and Content
RFC 7232: Conditional Requests
RFC 7233: Range Requests
RFC 7234: Caching
RFC 7235: Authentication
If you are looking for methods, status codes and headers definitions, then the RFC 7231 is the document you should refer to.
Having said that, let's go back to your question.
Should HTTP PUT create a resource if it does not exist?
It depends.
But, if your application generates resource identifiers on behalf of the client, as you mentioned in your question, then you should use POST instead of PUT for creating resources.
Some parts of the PUT method definition are quoted below. The last sentence seems to be the most relevant to you (highlight is mine), supporting what I've just mentioned above:
4.3.4. PUT
The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. [...]
If the target resource does not have a current representation and the PUT successfully creates one, then the origin server MUST inform the user agent by sending a 201 (Created) response. If the target resource does have a current representation and that representation is successfully modified in accordance with the state of the enclosed representation, then the origin server MUST send either a 200 (OK) or a 204 (No Content) response to indicate successful completion of the request. [...]
Proper interpretation of a PUT request presumes that the user agent knows which target resource is desired. A service that selects a proper URI on behalf of the client, after receiving a state-changing request, SHOULD be implemented using the POST method rather than PUT. [...]
Should I return a 404 error if the creation of the resource is not possible?
That's seems to be an accurate status code to be returned, as no representation has been found for the requested resource:
6.5.4. 404 Not Found
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. [...]
Now, for the sake of completeness, find below some relevant quotes on the POST method definition, which should be used to create resources in the scenario described in your question:
4.3.3. POST
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others):
[...]
Creating a new resource that has yet to be identified by the origin server;
[...]
If one or more resources has been created on the origin server as a result of successfully processing a POST request, the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created and a representation that describes the status of the request while referring to the new resource(s).
While the 201 status code indicates that a new resource has been created, the Location header indicate where the newly created resource is located. If no Location header is provided, then the client should assume that the resource is identified by the effective request URI:
6.3.2. 201 Created
The 201 (Created) status code indicates that the request has been fulfilled and has resulted in one or more new resources being created. The primary resource created by the request is identified by either a Location header field in the response or, if no Location field is received, by the effective request URI. [...]
In short, it depends wheter the payload you want to store violates any constraint the server has for resources or not.
In general I'd say it should attempt it as the client explicitly expresses his intent to store that particular representation at the target URI. The server should though perform constraint checks before! Usually, in a real REST scenario though, the client should use URI that are provided by the server and not just chose any URI on its own. Thereby, a server should be in control of its namespace, as such using PUT to create resources is not recommended here by default.
With that being said, as PUT is idempotent while POST being not, some clients might want to benefit from this property. Here a POST-PUT creation pattern has evolved, where a client is attempting to create a new resource via POST until it receives a confirmation via a Location header in the response and afterwards attempts the update of that resource's state via PUT. This way the client can be sure that in case of transmission problems the representation was only created once. Depending on the stance, some people might consider the actual update of the resource as the actual resource creation, though as the client beforehand received the respective link, this is not quite the case.
Note that a server also has the right to transform the representation to something different if i.e. the server is configured to provide specific representations for certain URI endpoints. Think of uploading an image via PUT to a URI and the server embedds the image into a HTML page
There's two questions embedded here: 1) should PUT try to create the resource and 2) what happens if it cant.
1)
The RFC linked by #cass says https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4:
The PUT method requests that the state of the target resource be
created or replaced with the state defined by the representation
enclosed in the request message payload. A successful PUT of a given
representation would suggest that a subsequent GET on that same
target resource will result in an equivalent representation being
sent in a 200 (OK) response.
Further, Mozilla's text https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT
The HTTP PUT request method creates a new resource or replaces a representation of the target resource with the request payload.
Further, from the original RFC (that was replaced with the above test) https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
This is a bit anecdotal, but the Kubernetes API also carefully makes this distinction and informs it's users of PATCH if they really meant update: https://kubernetes.io/docs/reference/using-api/api-concepts/#api-verbs
For PUT requests, Kubernetes internally classifies these as either create or update based on the state of the existing object. An update is different from a patch; the HTTP verb for a patch is PATCH.
2
In terms of "what happens if it fails" I think the code depends on what went wrong:
400: it couldnt be created due to a bad payload
409: it couldnt be created due to a conflict - for example some field in the input JSON has some global uniqueness check on it
502/3 - it couldnt be created because it tried to call the database and it was dead
I'm not sure if 404 is the best code, becuase it doesnt tell the user anything about why.
how to handle resource checking on server side?
For example, my api looks like:
/books/{id}
After googling i found, that i should use HEAD method to check, if resource exists.
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
I know, that i can use GET endpoint and use HEAD method to fetch information about resource and server does not return body in this case.
But what should i do on server side?
I have two options.
One endpoint marked as GET. I this endpoint i can use GET method to fetch data and HEAD to check if resource is available.
Two endpoints. One marked as GET, second as HEAD.
Why i'm considering second solution?
Let's assume, that GET request fetch some data from database and process them in some way which takes some time, eg. 10 ms
But what i actually need is only to check if data exists in database. So i can run query like
select count(*) from BOOK where id = :id
and immediately return status 200 if result of query is equal to 1. In this case i don't need to process data so i get a faster response time.
But... resource in REST is a object which is transmitted via HTTP, so maybe i should do processing data but not return them when i use HEAD method?
Thanks in advance for your answer!
You could simply delegate the HEAD handler to the existing GET handler and return the status code and headers only (ignoring the response payload).
That's what some frameworks such as Spring MVC and JAX-RS do.
See the following quote from the Spring MVC documentation:
#GetMapping — and also #RequestMapping(method=HttpMethod.GET), are implicitly mapped to and also support HTTP HEAD. An HTTP HEAD request is processed as if it were HTTP GET except but instead of writing the body, the number of bytes are counted and the "
Content-Length header set.
[...]
#RequestMapping method can be explicitly mapped to HTTP HEAD and HTTP OPTIONS, but that is not necessary in the common case.
And see the following quote from the JAX-RS documentation:
HEAD and OPTIONS requests receive additional automated support. On receipt of a HEAD request an implementation MUST either:
Call a method annotated with a request method designator for HEAD or, if none present,
Call a method annotated with a request method designator for GET and discard any returned entity.
Note that option 2 may result in reduced performance where entity creation is significant.
Note: Don't use the old RFC 2616 as reference anymore. It was obsoleted by a new set of RFCs: 7230-7235. For the semantics of the HTTP protocol, refer to the RFC 7231.
Endpoint should be the same and server side script should make decision what to do based on method. If method is HEAD, then just return suitable HTTP code:
204 if content exists but server don't return it
404 if not exists
4xx or 5xx on other error
If method is GET, then process request and return content with HTTP code:
200 if content exists and server return it
404 if not exists
4xx or 5xx on other error
The important thing is that URL should be the same, just method should be different. If URL will be different then we talking about different resources in REST context.
Your reference for HTTP methods is out of date; you should be referencing RFC 7231, section 4.3.2
The HEAD method is identical to GET except that the server MUST NOT send a message body in the response (i.e., the response terminates at the end of the header section).
This method can be used for obtaining metadata about the selected representation without transferring the representation data and is often used for testing hypertext links for validity, accessibility, and recent modification.
You asked:
resource in REST is a object which is transmitted via HTTP, so maybe i should do processing data but not return them when i use HEAD method?
That's right - the primary difference between GET and HEAD is whether the server returns a message-body as part of the response.
But what i actually need is only to check if data exists in database.
My suggestion would be to use a new resource for that. "Resources" are about making your database look like a web site. It's perfectly normal in REST to have many URI that map to a queries that use the same predicate.
Jim Webber put it this way:
The web is not your domain, it's a document management system. All the HTTP verbs apply to the document management domain. URIs do NOT map onto domain objects - that violates encapsulation. Work (ex: issuing commands to the domain model) is a side effect of managing resources. In other words, the resources are part of the anti-corruption layer. You should expect to have many many more resources in your integration domain than you do business objects in your business domain.
Let's clarify three common scenarios when no item matches the request with a simple example:
GET /posts/{postId} and postId does not exist (status code 404, no question)
GET /posts?userId={userId} and the user with userId does not have any posts
GET /posts?userId={userId} and the user with userId does not exist itslef
I know there's no strict REST guideline for the appropriate status codes for cases 2 and 3, but it seems to be a common practice to return 200 for case 2 as it's considered a "search" request on the posts resource, so it is said that 404 might not be the best choice.
Now I wonder if there's a common practice to handle case 3. Based on a similar reasoning with case 2, 200 seems to be more relevant (and of course in the response body more info could be provided), although returning 404 to highlight the fact that userId itself does not exist is also tempting.
Any thoughts?
Ok, so first, REST doesn't say anything about what the endpoints should return. That's the HTTP spec. The HTTP spec says that if you make a request for a non-existent resource, the proper response code is 404.
Case 1 is a request for a single thing. That would return 404, as you said.
The resource being returned in case 2 is typically an envelope which contains metadata and a collection of things. It doesn't matter if the envelope has any things in it or not. So 200 is the correct response code because the envelope exists, it just so happens the envelope isn't holding any things. It would be allowable under the spec to say there's no envelope if there are no things and return 404, but that's usually not done because then the API can't send the metadata.
Case 3, then, is exactly the same thing as case 2. If expected response is an envelope, then the envelope exists whether or not the userId is valid. It would not be unreasonable to include metadata in the envelope pointing out that there is no user with userId, if the API designer thinks that information would be useful to clients.
Case 2 and Case 3 are really the same case, and should both either return 200 with an empty envelope or 404.
First piece, you need to recognize that /posts?userId={userId} identifies a resource, precisely in the same sense that /posts/{userId} or /index.html specifies a resource.
So GET /posts?userId={userId} "requests transfer of a current selected representation for the target resource."
The distinction between 200 and 404 is straight forward; if you are reporting to the consumer that "the origin server did not find a current representation for the target resource or is not willing to disclose that one exists", then you should be returning 404. If the response payload includes a current representation of the resource, then you should use the 200 status code.
404 is, of course, an response from the Client Error response class
the server SHOULD send a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition.
So a way of figuring out which of these status codes to use, is to just look at the message body of the response. If it is a current representation of the resource, then you use the 200 status code. If it is a representation of a message that explains no current representation is available, then you use the 404 status code.
Of course that ducks the big question: what should the representation of the resource be in each case? Once you know that, you can work out the rest.
If you you think that an unexpected identifier indicates an error on the client (for example, a corrupted link), then it will probably improve the consumer's experience to report that as an explicit error, rather than returning a representation of an empty list.
But that's a judgment call; different API are going to have different answers, and HTTP isn't particularly biased one way or the other; HTTP just asks that you ensure that the response code and headers are appropriate for the choice that you have made.