User-centred API Design
I’ve seen a few thoughts on how to design an API recently, one in particular takes a very pragmatic approach that is pretty much exactly how I would build an API these days (and prompted me to finally drag this out of my Evernote drafts folder and onto my blog), but none quite cover the thoughts that have been brewing in my head whilst building the Xively API over the last few years (and thinking about the next version). These are more like high-level design approaches than specific technical recommendations - these are the things you need to think about before even putting code to terminal.
The big idea
There are going to follow a few more detailed concepts, but I thought I’d kick off with the underling principle of API design, which is:
The user is king (or queen)
We’re talking here about API design, but one of the first principles of successful design is to design with the user in mind (aka User-Centred Design). You wouldn’t expect any serious website to be designed without any thought for who was going to use it, so why do APIs often get seen as an afterthought, tacked on and unplanned? Putting yourself in the position of being the user is a good first start at understanding what it would be like to use your API, even better is if you can find some real users (if you’re in the lucky position of having some!) and ask them what they find difficult and try out prototypes on them. The other items in this list are all really themed around making your API as easy to use as possible. An easy API will mean that if you get people coming along to kick the tyres of your product, they get further and get a better impression of it. Imagine assessing two payment providers, say Stripe and PayPal. Which would you be most likely to use, given the choice? I’ll give you a clue - it probably wouldn’t be PayPal.
Reduce Surface Area
The more API endpoints you have, the more confused your users will be. If you’re unsure whether you should develop a specific piece of functionality, don’t. Wait until enough real users ask / beg you for it and then consider whether it is worth making your API more complex for everyone in order to build it.
Fail Fast (and Verbosely)
Never try to second guess what the user wants to happen if there is any uncertainty in the request because it just masks errors and makes users more confused in the long run. A good analogy here is in comparing PostgreSQL (one of my favourite pieces of software) and MySQL - if you try to enter an invalid date in Postgres it will give you a clear error message saying the date is invalid, whereas MySQL will silently coerce it to 0000-00-00 (make sure strict mode is enabled to avoid this). You know what they say about assumptions. Always return a clear error message. Instead of returning error codes, return links to specific pieces of documentation detailing that error more fully.
One way to do things
I’m going to use my own API as an example of what not to do here. At Xively we have a hierarchical relationship of Feeds > Datastreams > Datapoints. You can get Datapoints in to the system using three different endpoints and in about 6 different ways. We’ve recently been rewriting the documentation and have stripped the methods that we’re documenting (and recommending) down to 1 because we’ve realised the error of our ways. The next version of the API will definitely follow this mantra. It’s also good for the developer because it reduces application complexity and makes things much easier to maintain without having to deal with many, many edge cases.
Reduce the number of concepts
Every API has a number of concepts that users have to understand in order to be able to use it. It stands to reason that the length of time it takes to become fluent in an API is proportional to the number of concepts you have to grok first. REST is a good approach to this because it reduces the number of possible operations a user has to understand down to four. Then all they need to understand is what each object type is. If you compare REST to a more RPC based approach, then you often end up with a concept for every operation.
Don’t overload endpoints
Often, when trying to reduce the surface area of an API you end up tricking yourself into thinking you’ve achieved this by hiding functionality on existing methods. For example, using a GET parameter to change the behaviour of a specific endpoint. All you’ve done is made that endpoint more complex and harder to use because users now have to have a set of additional conditions baked into their understanding of the endpoint. This is a tricky one to solve though - the only real way of stopping it is to not add the functionality, so again, only build things you know users (and a reasonable amount of them, not just one loud one) really need.
Reduce the minimum requirements
Users should be able to get up and running with the minimum possible effort. This means that if you have, for example, a JSON or XML representation of a dat model and a lot of its attributes are required, then they will have to spend time and thought adding them all immediately. If you’re able to, make as many of the attributes optional as possible and then make sure you document the minimal way first. Which brings me on to…
Obviously you should have some. However, the best kind of documentation to get users started quickly is not the endpoint by endpoint manual, but quick start guides detailing how to do a specific commonly performed task. Task-oriented documentation is so much more useful than a manual because it gives the user the context of the action they are trying to perform and then walks them through all of the steps they might need to perform it. Typically this might consist of a number of actions which would be spread over a number of different pages in the manual, that the user would have no clue as to how to assemble into a coherent set of actions. Again, put the user first and think about what they are trying to achieve and then how you can best help them understand how to achieve it.
If you don’t start by putting the user first, then there’s no point in implementing any of the guides for how to build a good API because you’ll already have failed.