Let's say I have a simple Jersey REST resource as follows:
@Path("/foos")
public class MyRestlet
extends BaseRestlet
{
@GET
@Path("/{fooId}")
@Produces(MediaType.APPLICATION_XML)
public Response getFoo(@PathParam("fooId") final String fooId)
throws IOException, ParseException
{
final Foo foo = fooService.getFoo(fooId);
if (foo != null)
{
return Response.status(Response.Status.OK).entity(foo).build();
}
else
{
return Response.status(Response.Status.NOT_FOUND).build();
}
}
}
Based on the code above, is it correct to return a NOT_FOUND
status (404
), or should I be returning 204
, or some other more appropriate code?
Many thanks in advance!
A 404 response in this case is pretty typical and easy for API users to consume.
One problem is that it is difficult for a client to tell if they got a 404 due to the particular entity not being found, or due to a structural problem in the URI. In your example,
/foos/5
might return 404 because the foo with id=5 does not exist. However,/food/1
would return 404 even if foo withid=1
exists (becausefoos
is misspelled). In other words, 404 means either a badly constructed URI or a reference to a non-existent resource.Another problem arises when you have a URI that references multiple resources. With a simple 404 response, the client has no idea which of the referenced resources was not found.
Both of these problems can be partially mitigated by returning additional information in the response body to let the caller know exactly what was not found.
A
4XX
error code means error from the client side.As you request a static resource as an image or a html page, returning a
404
response makes sense as :As you provide to clients some REST methods, you rely on the HTTP methods but you should not consider REST services as simple resources.
For clients, an error response in the REST method is often handled close to errors of other processings.
For example, to catch errors during REST invocations or somewhere else, clients could use
catchError()
of RxJS.We could write a code (in TypeScript/Angular 2 for the sample code) in this way to delegate the error processing to a function :
The problem is that any HTTP error (5XX or 4XXX) will terminate in the
catchError()
callback.It may really make the REST API responses misleading for clients.
If we do a parallel with programming language, we could consider 5XX/4XX as exception flow.
Generally, we don't throw an exception only because a data is not found, we throw it as a data is not found and that that data would have been found.
For the REST API, we should follow the same logic.
If the entity may not be found, returning
OK
in the two cases is perfectly fine :The client could so handle the result according to the result is present or missing.
I don't think that returning
204
brings any useful value.The HTTP
204
documentation states that :But requesting a REST resource and more particularly by a GET method doesn't mean that the client is about terminating a workflow (that makes more sense with POST/PUT methods).
The document adds also :
We are really not in this case.
Some specific HTTP codes for classical browsing matche finely with return codes of REST API (201, 202, 401, and so for...) but this is not always the case. So for these cases, rather than twisting original codes, I would favor to keep them simple by using more general codes :
200
,400
.Yes, it is pretty common to return 404 for a resource not being found. Just like a web page, when it's not found, you get a 404. It's not just REST, but an HTTP standard.
Every resource should have a URL location. URLs don't need to be static, they can be templated. So it's possible for the actual requested URL to not have a resource. It is the server's duty to break down the URL from the template to look for the resource. If they resource doesn't exist, then it's "Not Found"
Here's from the HTTP 1.1 spec
Here's for 204
Normally 204 would be used when a representation has been updated or created and there's no need to send an response body back. In the case of a POST, you could send back just the Location of the newly created resource. Something like
The
created(URI)
will send back the response with the newly created URI in theLocation
header.Adding to the first part. You just need to keep in mind that every request from a client is a request to access a resource, whether it's just to GET it, or update with PUT. And a resource can be anything on the server. If the resource doesn't exist, then a general response would be to tell the client we can't find that resource.
To expand on your example. Let's say
FooService
accsses the DB. Each row in the database can be considered a resource. And each of those rows (resources) has a unique URL, likefoo/db/1
might locate a row with a primary key 1. If the id can't be found, then that resource is "Not Found"