• No results found

What Might Go Wrong?

In document RESTful Web Services pdf (Page 165-170)

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.

CHAPTER 6

Designing Read/Write Resource-

Oriented Services

In Chapter 5 I designed a fantasy web service that serves map images of various plan- ets,*navigation information for moving around the map, and information about places on the planets: restaurants, meteor craters, and so on. That’s a huge amount of data to serve, but it can all be contained in a premade data set. There’s nothing a user can do to put his own data on the server.

Clients for the map service in the previous chapter can do all sorts of interesting things with maps and places, but they can’t rely on the server to track anything except the preset data. In this chapter I expand the scope of the map service. It becomes less like a search engine’s web service and more like Amazon S3 and the Flickr and del.icio.us APIs. It not only serves data, it stores data on its clients’ behalf.

How open should I make the new service? A totally open service would allow users to provide their own versions of everything in the standard data set. Clients could create their own planets, and upload custom maps and databases of places. If I was too lazy to find map data myself (I am), I could even start with an empty database and allow the community to populate my entire data set. That’s what del.icio.us and Flickr did. Is this a good idea? When designing a web service, which levers of state should you expose, and which should you keep to yourself? That depends on what your users want to do, and how much of their applications you’re willing to write for them.

A client uses a web service because the service has something it wants: some data, a place to store data, or a secret algorithm. A web service is an abstraction layer, like an operating system API or a programming language library. If you wrote a math library for working with infinite series, and all your users started using it to estimate the value of π, you’d probably add that feature as a higher-level library function. That way all

* Remember, I’m using “planets” as a shorthand for “bodies that can be addressed with longitude and latitude.”

I don’t just mean whatever 8 or 11 bodies the International Astronomical Union has decided are planets this week.

your users could use the same well-tested π-estimation code instead of each person writing his or her own implementation. Similarly, if all your users implement the same features on top of your web service, you might help them out by moving those features into the service. If all your users want to add certain kinds of custom data to the data set, you can start supporting a new kind of resource, so they don’t have to define their own local structures.

My goal here is fairly modest: to illustrate the concepts of resource-oriented service design. It’s certainly possible to design a mapping service that starts off with an empty data set and gets everything through user contributions, but such a service would have more moving parts than I’ve got concepts to explain. If I decided to show you that service, this chapter would start out well, but once I’d explained all the concepts I’d still have a lot of domain-specific design work to do, and it would get boring.

I want the map service to have about as many moving parts as I have new concepts to explain. I’m going to expand the previous chapter’s service just enough so that clients can annotate the map with custom places. Every custom place is associated with a user account, and may be public or private to that account.

In document RESTful Web Services pdf (Page 165-170)