Want to Build a Better Web API? Build a Client Library!

A solid web API can be an important thing to have. Not only is it great to give users direct access to their data, but exposing data and operations via a web API enables your users to help themselves when it comes to building functionality that doesn’t really make sense in the application itself (or functionality that you never really thought of). It’s also a great way for users to get more familiar with your service.

However, if your API sucks, you can rest assured that nobody will touch it. We’ve all had to deal with crappy web APIs, the ones that make you jump through hoops in order to perform a task that should be dead simple to do. Web APIs should make the simple tasks easy, and the hard tasks possible. To add to the challenge, APIs are notoriously difficult to change. Even with a solid versioning scheme, it is often a real chore to get your users to stop using the deprecated API in favor of the new version. So, it’s important to do a good job the first time.

When building a web API, identifying the tasks that one might want to perform can sometimes be difficult to see when you’re surrounded by JSON, XML, GETs, POSTs, PUTs, DELETEs, and HTTP status codes. While it can be easy to see what single actions you would want to expose, seeing how those actions may interact with each other can be much more difficult. Sometimes you need to take a step back, away from the land of HTTP, in order to see your API as another programmer would see it.

Building a client library that wraps your web API is a great way to do this. It’s relatively easy to imagine how your requests and responses could be represented as objects. The largest benefit of this exercise is to take it a step further, and give the user of your client library the ability to determine what they should do next. Simply knowing if an API call succeeded or failed is usually not enough. Users of your client library need to be able to determine why the request failed, and understand what they can do about it. This extends well beyond the lifecycle of a single HTTP request and response.

Communicating errors

There are several different ways to communicate errors to the user. The proper use of HTTP status codes is one such way. The 4xx class of status codes are specifically intended to be used to communicate that something was wrong with the client’s request. If your API methods are simple, and specific in their purpose, you may be able to rely on HTTP status codes alone to communicate the various causes of failure to the client.

If your API method is complex, and could result in many different failure scenarios, you should first try to break it down into smaller, more specific API methods :) If that can’t be done, then another option is to return some easily parseable text in the response body (JSON or XML) that includes an error code that identifies the specific failure scenario. The response body could be as simple as:

{ "error_code" : 123 }

You could also provide a description of the error in the response as well. This helps users getting started with the API, saving them from having to constantly refer to your API’s documentation every time they get an error:

  "error_code" : 123,
  "error_message" : "A widget with that name already exists"

The important thing is that all failure cases be easily identifiable via a specific, documented code (HTTP status code or custom error code). Error messages should be seen as purely supplemental information. At no point should your users have to parse the error message to determine what happened, or what they should do next.

Isn’t this the same as “dogfooding”

Not exactly. Dogfooding simply involves using what you have created. You could easily dogfood your web API by firing HTTP requests at it using a simple HTTP client library. It is not until you need to take different actions based on different responses that you really start to see if you are properly communicating the result of the request. Building a client helps with this because it forces you to think about the different results and error scenarios in order to decide how your client should handle them. Which failures should raise exceptions? What sort of exception should be raised? How should non exceptional failures be communicated to the caller?

The next step in this process would be to build an application that uses your client library. That step could help identify issues with your client library, just like building the client library helps identify issues with your web API.

The client library

Oh, and don’t forget. At the end of the day, you’ll end up with a better designed web API, AND a great client library that your users can use to interact with your system. Not a bad deal!

3 thoughts on “Want to Build a Better Web API? Build a Client Library!

  1. This is a great post John.

    I also think it’s interesting thinking about building a client library across multiple languages and how your thoughts about the API methods might change. Think that would have any impact?

  2. Not sure…that’s a good question. My gut tells me that not a whole lot would change with regards to the web API. But, I’ve yet to go down that road…

  3. wrt consuming your API from multiple languages, great point. Consuming your API from Javascript and C# alone provide not only the “not a bad deal!” of lowering the barrier to entry for consumers, but are immediately faced with the crazy formatting of types that you’d consider serialized “right” by Microsoft, ie Dictionary, which using DataContractSerialization (DCS) serializes like an array of key value pairs, which is a far cry from what you will/would get from an API developed using Node.JS, which also means that the Javascript consumer is going to have some not-out-of-the-box deserialization of the Dictionary. Facing such a look at my API, I found that the serialization of ServiceStack wasn’t just the fastest JSON, but also the most interoperable, serializing Dictionary as PHP or Javascript or Python would, as a hash, as it would an object. Which leads to…the fact that the good deal is not just lowering the barrier to entry; it is also drawing on the geniuses from whatever language camp they settled down in.

Leave a Reply

Your email address will not be published. Required fields are marked *