I also need to plan for requests I can’t fulfill. When I hit an error condition I’ll send a response code in the 3xx, 4xx, or 5xx range, and I may provide supplementary data in HTTP headers. If they provide an entity-body, it’ll be a document describing an error condition, not a representation of the requested resource (which, after all, couldn’t be served).
I provide a full list of the HTTP response codes in Appendix B, along with examples where you might use each of them. Here are some likely error conditions for my map application:
• The client may try to access a map that doesn’t exist, like /road/Saturn. I under- stand what the client is asking for, but I don’t have the data. The proper response code in this situation is 404 (“Not Found”). I don’t need to send an entity-body along with this response code, though it’s helpful for debugging.
• The client may use a place name that doesn’t exist in my database. The end user might have mistyped the name, or used a name the application doesn’t recognize. They may have described the place instead of naming it, they might have the right name but the wrong planet. Or they might just be constructing URIs with random strings in them.
I can return a 404 response code, as in the previous example, or I can try to be helpful. If I can’t exactly match a requested place name, like /Earth/Mount%20Rush more%20National%20Monument, I might run it through my search engine and see if it comes up with a good match. If I do get a match, I can offer a redirect to that place: say, /Earth/43.9;-95.9/Mount%20Rushmore.
The response code for the helpful case here would be 303 (“See Other”), and the HTTP response header Location would contain the URI of the resource I think the
client was “really” trying to request. It’s the client’s responsibility to take the hint and request that URI, or not.
If I try a search and still have no idea what place the client is talking about, I’ll return a response code of 404 (“Not Found”).
• The client may use logically impossible latitudes or longitudes, like 500,-181 (500 degrees north latitude, 181 degrees west longitude). A 404 (“Not Found”) is a good response here, just as it is for a place that doesn’t exist. But a 400 (“Bad Request”) would be more precise.
What’s the difference between the two cases? Well, there’s nothing obviously wrong with a request for a nonexistent place name like “Tanhoidfog.” It just doesn’t exist right now. Someone could name a town or a business “Tanhoidfog” and then it would be a valid place name. The client doesn’t know there’s no such place: one of the nice things a client can do with my map service is check to see which places really exist.
But there is something wrong with a request for the latitude/longitude pair 500,-181. The laws of geometry prevent such a place from ever existing. A mini- mally knowledgeable client could have figured that out before making the request. A 400 response code is appropriate in that case: the problem is the client’s fault for even making the request.
• A search for places on a map might return no search results. There might be no racing speedways near Sebastopol, CA. This is disappointing, but it’s not an error. I can treat this like any other search: send a 200 response code (“OK”) and a rep- resentation. The representation would include a link to the place that was searched, along with an empty list of search results.
• The server may be overloaded with requests and unable to fulfil this particular request. The response code is 503 (“Service Unavailable”). An alternative is to refuse to handle the request at all.
• The server may not be functioning correctly. This might be due to missing or cor- rupted data, a software bug, a hardware failure, or any of the other things that can go wrong with a computer program. In this case the response code is 500 (“Internal Server Error”).
This a frustrating response code (the whole 5xx series is frustrating, actually) be- cause there’s nothing the client can do about it. Many web application frameworks automatically send this error code when an exception happens on the server side.
Conclusion
I’ve now got a design for a map web service that’s simple enough for a client to use without a lot of up-front investment, and useful enough to be the driver for any number of useful programs. It’s so closely attuned to the philosophy of the Web that you can
use it with a web browser. It’s RESTful and resource-oriented. It’s addressable, state- less, and well connected.
It’s also read-only. It assumes that my clients have nothing to offer but their insatiable appetites for my data. Lots of existing web services work this way, but read-only web services are only half the story. In the next chapter I’ll show you how clients can use HTTP’s uniform interface to create new resources of their own.