There was a recent post on ReadWriteCloud about 10 common mistakes made by API providers. I think this is a very thoughtful post, but I think it’s an inward look at the problem. In other words, they are looking at problems that developers face while implementing their own APIs. I think biggest mistakes are not necessarily how to implement your API, but how API consumers will perceive, implement and use the API. So I came up with my own list based on nearly a decade of implementing APIs from the receiving end.
Guest author Marcelo Calbucci is the Chief Startup Officer at Conceivian, a Seattle-based Startup Lab, and the founder of Seattle 2.0, an organization providing resources for tech entrepreneurs and startups. Marcelo is also a software developer since the age of 12. You can follow him @calbucci.
1) Naming Convention
Naming convention in the software world is a debate as old as the first programming language was invented. Independent of which convention you use, be consistent. It’s very annoying to implement an API that uses lowercase for all XML elements and attributes, except for a couple of them. Any developer can tell you stories of countless hours chasing a bug because of case-mismatch. My preference is all lowercase because it helps with HTTP compression.
2) URL Consistencies
This is similar to naming convention, and it’s just too common to see APIs where the URL stems and query string have not a strong logic to it. As in, to get users use api.mydomain.com/getusers.php, but to get pictures use api.mydomain.com/pictures/get.php. A little bit of thought goes a long way, even if you are starting with a single API. Thinking as „objects“ and „actions“ is a good start.
I love APIs that just ask me to pass a single API-Key on the URL. It’s much simpler than having to do some digest authentication (although digest is simple too), and a lot of heck simpler than having to do a separate call to get a session cookie to use on subsequent calls.
Some engineers over-think and over-engineer the problem. YouTube used to have a beautifully simple API where you could get meta-data from a YouTube video. Now they decided to normalize and use the Google standard ATOM response, which is pretty awful and bloated. Awful and bloated is one of the reasons SOAP has not caught up. Trying to create a common response for all APIs is silly. Getting user information is different from getting a video information, which is different from posting a comment, which is different from getting a list of followers. Keep it obvious. Keep it simple.
5) Object normalization
If you are going to return an object of type User on the XML element (or JSON) then make sure that every API that returns the element is consistent and returns similar fields. It’s very hard when the same provider has three different APIs that might return a similar, but not the same object. It means I have to parse it three different ways. Making attributes/values optional is fine, but don’t overload their meaning.
This is the most awful part of implementing APIs, particularly for newly released APIs. Don’t make me figure out how each call, each element and each attribute works. I spend way too much time looking into many responses to see what’s optional, what’s not, what’s the date format, is it a string or an integer, is it long-lat or lat-long, etc. It doesn’t have to be an extensive MSDN-like documentation, but clearly stating what are the call parameters, what values are valid, what are the default values, and on the response side giving an XML-response example and describing what each element/attribute is.
7) Be Forward and Backward Thoughtful
Don’t break my code! There is nothing worse when using a third-party API to learn that your live production code stopped working because the provider changed how an API works. It can be as simple as a change on the format of an element or sometimes as bad as a new XML format that is completely different from the previous format. I know you wrote on your blog, told on your Twitter account and, maybe, emailed everyone you could about this change, but don’t assume people pay attention to that. The best way is to make sure the URL itself has versioning, as in api.mydomain.com/1/myapi.xml. Be committed to keep old versions for at least six months after you release a new version and be very proactive at alerting consumers of your API.
8) Error Messages Are Important
There are two points I want to make: First, „Internal Error“ is not a satisfactory error message, and, second, don’t overload the meaning of HTTP response status codes. The best error messages have both an English description of what they are and a parser-friendly code, as in „783“. I don’t want to parse English-language error messages to figure out what I should tell my user. A standard error code to indicate the Full-Name field must be present is much better. Now, we might get into preferences now, but I prefer every HTTP call to respond with status code 200 and error messages to be embedded inside of the response body (or on an HTTP header), but using 401, 403, 500 to indicate success or error is just confusing. The HTTP status code is not supposed to understand the semantic inside of the response.
9) Making it Parsing Friendly
It’s important to remember as an API provider, that the cost of generating the output might be different from the cost of receiving that output and converting into a usable data structure. This goes both for the computational cost and for the implementation (lines of code) cost. Stay clear of custom date-time formats, stay clear of creating custom data types (for example, multiple pieces of information concatenated into a single string, e.g. „374|Mike Wallace|yes“). It also means don’t get too creative of embedding a CSV file inside a JSON inside an XML.
10) Allow for Subsets
I really like when APIs give me the ability of choosing a subset of data on the response. Amazon e-commerce API supports that and it’s great because if you just need a few fields back why would you get a 30Kb response? Depending on how I’m using the API, the CPU, network and monetary costs can be significant for me. I might also have some of the data cached, so returning a „user-id“ might be enough instead of returning a full „user“ object.
I don’t think this is an extensive list of best practices of implementing your own API for others to consume, but I think the more you wear the hat of the consumer side of things, the more adopted your API will be. Before you even start implementing your API think of three or four applications that would be built using it, and understand what the needs would be. Maybe you should go ahead and use a bit of test-driven development, on this case usage-driven development, and implement those applications first.