Here at Backupify, we consume many web APIs. Since we are in the process of building our own API, I thought it would be useful to list some of the features we consider important from a usability standpoint (think UX for APIs). Hopefully this will spur some discussion to help us address other usability concerns prospective developers might have.
Don’t reinvent the wheel here. If you use something standard, then developers will be familiar with it and be quicker to get up to speed. Even with a complex standard like OAuth, using a third-party toolkit means that after you’ve done it once, it’s pretty trivial thereafter.
Being rigorous about your API versioning can only benefit your users. No one likes to have their code mysteriously break on them due to changes in an API. That said, there are ways to make providing a versioned API easier for your users (as well as easier on yourself).
- Fork a new (major) version whenever there is a breaking change – this includes behavior- or field-modification or removal.
- Bump a minor version number for non-breaking changes (behavior or field additions), as a courtesy to your users. Typically you’ll only let the user select a major version of the API to use, but you can let them know the minor version in the response.
- Allow multiple ways to specify version – i.e. request headers (more restful) and URLs (more user-friendly)
- Provide a way for users to always employ just the latest version of your API (default version to latest).
- Make it easy for code to tell what version of an API is being used – i.e. version string in response header, and git checksums for the minor version.
- Have a well-documented phase-out period for old API versions, and actually stick to it.
3. Response Headers
Response headers are a convenient place to stick information that you’d like your users to see on every request. They’re also a good place to put operational data like the major.minor version string and throttling limits, e.g.
$ curl -i http://api.myapp.com
HTTP/1.1 200 OK
Status: 200 OK
X-OAuth-Scopes: read, write
I’m not sure if the above header names are de-facto standards, but github uses them, so that’s good enough for me.
If you have to throttle requests, make it easy to determine limits. Response headers are my preferred location for this data. API endpoints also work for this, but make sure they don’t count against the API limit.
When possible, it’s nice to allow the user to select what data format they want to receive the response in, with a reasonable default. Using a document builder pattern helps a lot here. For example, in a ruby project, the rabl gem makes it very easy to provide both XML and JSON(p) output formats. You should also make sure to format exceptional/error response in the same format the data was requested in to make it easier for your users to see/parse those responses without parse exceptions.
6. Consistent parameter naming
If you have pagination parameters on some API calls, make those parameters the same for all API calls that need it. Likewise, any other cross-cutting parameters should be consistent across your API.
This is key. Document all the endpoints and data formats, across versions, highlighting changes between versions. It’s also very nice to provide a live console for API exploration against real data.
Are there other elements of a successful API you think we missed? Do you disagree with some of our API standards? We welcome your feedback in the comments section.