REST principles - returning a simple response - rest

I'm working with Django REST framework. By default, all the requests returns a JSON object containing the pagination (prev, next, count, results). This is useful in 90% of the cases where the user retrieves or creates info about something. However, there are a few resources which don't have to return anything but rather a confirmation that everything went smoothly - for example, imagine a resource which is just a heartbeat request ("ping") to maintain the session active.
Would it be okay to return a simple response, such as {result: true} (without any pagination like the rest of resources have) or would this be an eventual violation of the REST principles?

If all you want is to know if the URI is fully serviceable, disregarding the body completely, you should simply support a HEAD request instead of GET.

Yes, ouf course such a response to a ping request is OK. Pagination is something only suitable for a collection that can be paged. Paging An unique resource that is not a collection does not make sense.
For the ping request you could even leave the response body empty.
Request:
GET /ping
Response:
200 OK
Content-Length: 0

Pagination should be solved with range headers or hyperlinks. You don't need the body in empty responses, just the status header.

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.

REST Check if resource exists, how to handle on server side?

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.

ETags and collections

Many REST APIs provide the ability to search for resources.
For example, resources of type A may be fetched using the following HTTP request:
GET /A?prop1={value1}&prop2={value2}
I'm using optimistic locking and therefore would like to return a version for every returned resource of type A. Until now, I used the ETag header when fetching only one resource using its ID.
Is there an HTTP way for returning version for multiple resources in the same response? If not, should I include the versions in the body?
Thanks,
Mickael
EDIT: I found on the web that the ETag is often generated by computing a hash of part of the reply. This approach fits well with my case since a hash of the returned collection will be computed. However, if the client decides to update one of the elements in the collection, which ETag should he put in the If-Match header? I'm thinking that including the ETags of the individual elements is the only solution...
I would adopt one of these options:
Make ETags weak by default and they are generated with the resource current state, not with the resource representation in the HTTP response payload. With that, I can return a valid ETag for each resource in the collection query response body, besides the ETag for the whole collection in the response header.
Forget If-Match and ETags for this case and use If-Unmodified-Since with a Last-Modified supplied as a property of each resource. By doing that I can preserve the strong ETags, but clients can still make updates to one item based on the collection response without the need for another request to the resource itself.
Allow updates via PATCH on the collection resource itself, using the If-Match header with the ETag for the whole collection. This probably won't work very well if there's a lot of concurrent changes, but it's a reasonable approach.
I think it depends a little bit on the amount of resources, data and requests to reduce bandwith. But a solution could be to separate the resources in sub-requests.
Assume that the group call of GET /images?car=mustang&viewangle=front returns 5 images. Now you could include all images as binary data and the GET-request itself has a unique ETag:
GET /images?car=mustang&viewangle=front
...
HTTP 1.1 200 OK
ETag "aaaaaa"
data:image/png;base64,a123456....
data:image/png;base64,b123456....
data:image/png;base64,c123456....
data:image/png;base64,d123456....
data:image/png;base64,e123456....
The problem is now, that one added image changes the ETag of the group call and you need to transfer the complete set again altough only one image has changed:
GET /images?car=mustang&viewangle=front
If-None-Match "aaaaaa"
...
HTTP 1.1 200 OK
ETag "bbbbbb"
data:image/png;base64,a123456....
data:image/png;base64,b123456....
data:image/png;base64,c123456....
data:image/png;base64,d123456....
data:image/png;base64,e123456....
data:image/png;base64,f123456....
In this case the best solution would be that you separate the resources data from the group call. So the response includes only information for sub-requests:
GET /images?car=mustang&viewangle=front
...
HTTP 1.1 200 OK
ETag "aaaaaa"
a.jpg
b.jpg
c.jpg
d.jpg
e.jpg
By that every sub-request can be cached separatly:
GET /image/?src=a.jpg
If-None-Match "Akj5odjr"
...
HTTP 1.1 304 Not Modified
Statistics
- First request = 6x 200 OK
- Future requests if group unchanged = 1x 304 Not Modified
- Future requests if one new resource has been added = 2x 200 OK, 5x 304 Not Modified
Now I would tune the API documentation. This means the requester must check if a cache of a sub-request is available before making a call to it. This could be done by providing the ETags (or other hash) in the group request:
GET /images?car=mustang&viewangle=front
...
HTTP 1.1 200 OK
...
ETag "aaaaaa"
a.jpg;AfewrKJD
b.jpg;Bgnweidk
c.jpg;Ckirewof
d.jpg;Dt34gsd0
e.jpg;Egk29dds
f.jpg;F498wdn4
Now the requester checks the cache and finds out that a.jpg has a new ETag called Akj5odjr and f.jpg;F498wdn4 is a new entry. By that future requests are reduced:
Statistics
- First request = 6x 200 OK
- Future requests if group unchanged = 1x 304 Not Modified
- Future requests if one new resource has been added = 2x 200 OK
Conclusion
Finally you need to think about if your resources are big enough to put them in sub-requests and how often one requester repeats bis group request (so the cache is used). If not, you should include them in the group call and you do not have room for optimization.
P.S. you need to monitor all requesters to be sure all of them use caches. A possible solution would be to ban requesters calling an API URL two or more times without sending an ETag.

find-or-create idiom in REST API design?

say we have a 'user' resource with unique constraint on 'name'. how would you design a REST API to handle a find-or-create (by name) use case? I see the following options:
option 1: multiple requests
client:
POST /user
{"name":"bob"}
server:
HTTP 409 //or something else
client:
GET /user?name=bob
server:
HTTP 200 //returns existing user
option 2: one request, two response codes
client:
POST /user
{"name":"bob"}
server:
HTTP 200 //returns existing user
(in case user is actually created, return HTTP 201 instead)
option 3: request errs but response data contains conflicting entity
client:
POST /user
{"name":"bob"}
server:
HTTP 409 //as in option1, since no CREATE took place
{"id": 1, "name":"bob"} //existing user returned
I believe the "correct" RESTful way to do this would be :
GET /user?name=bob
200: entity contains user
404: entity does not exist, so
POST /user { "name" : "bob" }
303: GET /user?name=bob
200: entity contains user
I'm also a big fan of the Post-Redirect-Get pattern, which would entail the server sending a redirect to the client with the uri of the newly created user. Your response in the POST case would then have the entity in its body with a status code of 200.
This does mean either 1 or 3 round-trips to the server. The big advantage of PRG is protecting the client from rePOSTing when a page reload occurs, but you should read more about it to decide if it's right for you.
If this is too much back-and-forth with the server, you can do option 2. This is not strictly RESTful by my reading of https://www.rfc-editor.org/rfc/rfc2616#section-9.5:
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.
If you're okay with veering away from the standard, and you're concerned about round-trips, then Option 2 is reasonable.
I am using a version of option 2. I return 201 when the resource is created, and 303 ("see other") when it is merely retrieved. I chose to do this, in part, because get_or_create doesn't seem to be a common REST idiom, and 303 is a slightly unusual response code.
I would go with Option 2 for two reasons:
First, HTTP response code, 2xx (e.g. 200 nd 201) refers to a successful operation unlike 4xx. So in both cases when find or create occurs you have a successful operation.
Second, Option 1 doubles the number of requests to the server which can be a performance hit for heavy load.
I believe a GET request which either:
returns an existing record; or
creates a new record and returns it
is the most efficient approach as discussed in my answer here: Creating user record / profile for first time sign in
It is irrelevant that the server needs to create the record before returning it in the response as explained by #Cormac Mulhall and #Blake Mitchell in REST Lazy Reference Create GET or POST?
This is also explained in Section 9.1.1 of the HTTP specification:
Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them.

REST status code 204 on paginated result

I am designing a REST like API for paginated data retrieval of a YUI-based client.
The REST URL looks like this for a GET request:
/app/catalog/data?startIndex=<int>&results=<int>&sort=<sting>&dir=<string>
All parameters are optional, i.e. if no parameters are given, all data from DB will be dumped.
Now say that there are only 1000 records in the database. Following reqeust is made:
/app/catalog/data?startIndex=1100&results=25
What status code should I return if the paginated result from the database remains empty though the request was fine?! I can't decide whether this is 204 or 404.
The produced media types are JSON and CSV.
I would say 204 is most appropriate. The request was successful, just with no results.
10.2.5 204 No Content
The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation.
Sounds exactly like the case.
I can't decide whether this is 204 or 404.
Neither. Just return 200 with an empty result (empty XML document or JSON array, whatever you use). Typically I use REST services with paginated views so along with results page I return total number of records. This will help clients to realize the mistake. But technically it is nothing wrong.
Use 204 for DELETE operations (there's really no content to return) and for PUT.
BTW (bold mine):
if no parameters are given, all data from DB will be dumped
Believe, you don't want to do this...
What format do you normally return your results in? I'd be inclined to make this 204 or even 200 returning an empty list.
HTTP 204 in pagination response is not factible because of the payload. When paginating you should return pagination information like, items returned, total items, offset, etc. which makes no sense with HTTP 204.
HTTP 204 is useful on resource updates (ie PUT) when you want to explicitly say that the resource does not need to be fetched again (GET). For example, resources that have calculated fields and require a refresh of the view after every update, fetching those calculated fields from the server. Therefore, the 204 status code has specific use cases and must be designed and documented.
I would use one of:
HTTP 200 with count=0 and no items in the returned list.
HTTP 400 because invoker asked for an url that is invalid
HTTP 404 because items to return are not found
Choose the one that best suits the way your API works.
I think it's safe to return an error (4xx + error info) in this situation because the offset can be exceeded by one of these assumptions:
A coding error
Invoker is not fetching data from begining (no fresh state)
Invoker ignored pagination data (present on each response)
You are not using total field in the response (which is optional because there are some situations where you can not count all items or simply it's very expensive counting them). In this case, if your last page has the same number of items (count) as the number of items asked for in the request (limit), there is no way to know that this is the last page, so you try another one. In that last request you will get a count=0 in the response and you can stop asking for pages. This case makes it fair to return a 200 code also because the programmer did exactly what you asked for in the API documentation.