About the Author

author photo

Adam Trachtenberg is the Director of the LinkedIn Developer Network, where he oversees developer relations and marketing for the LinkedIn Platform. Before LinkedIn, Adam worked at eBay in platform product management and marketing. Even earlier, he co-founded Student.Com and TVGrid.com. Adam is the author of PHP Cookbook and Upgrading to PHP 5. He lives in San Francisco.

See All Posts by This Author

REST Web Services, the Book

feature photo

Sam Ruby and Leonard Richardson are writing a book on REST Web services. Very exciting. I love reading Sam’s blog and watching him untangle standards.

Looking at the Table of Contents, I’m particularly interested in “Appendix A: HTTP status codes and when to use each one.” (Yes, I am serious.)

When I designed “Dude, Where’s My Used Car,” my mashup between eBay Motors and Google Maps, I churned through a number of different ways to signal failure. My biggest issue is that there’s so many places my request can fail, I’m not sure how to “correctly” represent that back inside my mashup.

For example, in response to a user-generated action (such as filling out a form and clicking submit), my mashup initiates a HTTP GET AJAX request (well, AJAJ because I’m using JSON instead of XML) which hits my web server. I then use PHP to parse the request, generate a corresponding SOAP request to eBay’s web service gateway, wait for result, pick it apart and convert the bits I want to JSON. This data is then passed back to the browser, where I (well, Dojo, actually) evals it.

When everything works, everything works.

But what happens when the user enters an invalid ZIP Code? eBay will return an error, and I’d like to proxy this back to the application, so I can toss up a message.

Should I return 200 OK and pass back the message? That’s one option, but I’d prefer not to need to check the data structure to see if I got the normal data I expected or some nasty error instead.

Besides, Dojo lets me specify a separate error handler callback function. It seems a cleaner design to handle all the errors there. But then I can’t return 200. What to use instead? 400 Bad Request?

Then there’s cases where the error is not the user’s fault, but either my fault or eBay’s fault. What should I do if eBay returns a SOAP envelope my PHP script can’t parse? 502 Bad Gateway? Or if the eBay server returns a SOAP Fault? The same 500 Internal Server Error I got back from eBay?

Should I not let my web server’s interaction with eBay bleed back into browser?

Here’s another example: when eBay’s server is too busy, it returns Error Code 10007. I can retry (and hopefully fix the problem) inside of my PHP script without even needing to message back to the browser. But if I did ultimately give up retrying, should I pass back 503 Service Unavailable? Am I on the hook for translating between SOAP and REST in my server-side proxy PHP script?

Maybe I can use 4xx codes for problems which are “user generated” in some form. These are things which require the user to take an action to remedy. And for things which are broken but otherwise outside of the control of the user (such as my SOAP client being unable to understand eBay’s SOAP response) I can use 5xx.

I actually like this idea, but I’m wondering if there’s a “standard” way to indicate errors and failures in a AJAX application. I can’t find one, but I’m not very familiar with what’s out there.

PS: My vote is to leave off the “With Ruby” part of the title, and go with plain “REST Web Services”.

There Are 5 Responses So Far. »

  1. An overview of the status codes can be found in rfc 2616 (http://rfc.net/rfc2616.html#p58). Status codes starting with 4 are used when the error seems to be on the client side, codes starting with 5 should be used for server errors.

  2. If you send me your email I’ll send you the current version of the appendix. There’s also a list of status codes in “HTTP: The Definitive Guide”. I haven’t actually gone through that list and normalized it against the appendix.

  3. Jörn —

    Makes sense. Where I run into issues is around the phrase “client seems to have erred.” Is this referring to the format of the request or its content? Or both?

    If I have something that’s valid HTTP, but the data that’s provided is invalid for the web service, is that 2xx or 4xx? The client generated a valid request structurally, but the user operating the client made the client pass along invalid data.

    Likewise, what happens when I have stacked clients and servers? My PHP script is both a server (processing AJAX requests from the browser) and a client (sending SOAP requests to eBay). If there’s a client error (4xx) between me and eBay should that turn into a server error (5xx) between me and the web browser? Or stay a client error?

    Should I not expose this nature to the browser? I am thinking not, as why should it matter if the data is being gathered from a web service or a database, but I want to make sure.

  4. I think that a wellformed HTTP can also result in a 4xx kind of error, like a request for a non-existent resource which results in a 404. This would seem like a good solution to your example of an invalid zip code. The combination of search parameters results in a url like ‘search?zip=12345’ and an 404 status would be the expected outcome of manually modifying an url.

    Of course this would only work if the upstream server reports meaningful error messages or additional fault codes that one can map to client errors. If I could not trace the error back to some faulty parameters the client supplied, I would return a 5xx status code.

  5. I know I’m very late to this discussion, but I would argue that a 404 error for a zip code that doesn’t exist is inappropriate for GET /search?zip=12345 because the resource /search technically exists. However, if you changed it to GET /search/zip/12345, then a 404 error is completely appropriate because the /search/zip/12345 resource does not exist. I do not think the query string is part of the requested resource even though it affects the requested resource.