(One of my summaries of a talk at the 2018 european djangocon.)
Our applications are increasingly also used by other computers. But the APIs they use are ironically aimed at humans: at the programmers that have to program on your API.
“API” means “application programming interface”, but it might be better to say “application programmer interface” as you really have to focus on the programmer that has to do the programming!
What makes an API good?
Documentation.
Familiarity.
Lack of friction.
This is often overlooked. But it is the first point of contact of your API, so it gives the first impression. An important deciding factor. It takes lots of work to write good documentation, but the effort is worth it.
Look at your documentation as a “sales page” for your API. What do you want on your sales page? Here are some suggestions:
How do I access it?
Do I need authentication? How?
What is the root URL?
General info on encodings and formats. Make it explicit.
Pagination.
Document the common errors (error codes) you can get.
Code for getting started. It gives your users a warm feeling if their first try works right away.
When you document the endpoints, show the URL and the available operation. Also show the request and response data formats. Don’t forget the optional parameters. When permissions change what you can do with an endpoint: mention it.
How do you keep your documentation up-to-date? The solution is to automatically generate the documentation. The common solution is to first generate a machine-readable schema out of your code and then generate documentation out of the schema.
OpenAPI and swagger are two tools you could use. But he advises to look at your own (django) tools first: what is available in there?
Once you have a schema, you could look at generating client libraries…
Important: standardization! People are used to exiting APIs. Familiarity helps.
You could look at http://jsonapi.org, “a specification for building APIs in json”. GraphQL is another option. (So: jsonapi.org is just an example.)
A standard structure (as suggested by jsonapi.org) helps, like a links
item in the result with prev/next URLs for the next/previous paginated
pages. Then a data
item with type, ID, self-url, attributes, further links
etc.
If you requested a single item (/projects/12
) you get a single item in
data
, if you requested a collection (/projects
), data
should be a
list.
The big advantage is that every API that uses this standard feels familiar. It is easier to work with.
jsonapi.org has support for limiting the number of returned fields
(?fields=name,id
) and for including nested data
?include=comments
. Essential if you want to tweak the output for better
performance.
Errors will happen. How easy it is to react to errors is quite important in reducing friction. jsonapi.org lets you return nice usable errors.
Friction can also happen when you work with large datasets. jsonapi.org
suggests to add out-of-band URLs (/download/all-the-data.tgz
).
Friction can also come from differences between versions of your API. The best you can do is to build in versioning right from the start. There are a couple of approaches:
Use headers. AcceptHeaderVersioning
like django rest framework uses.
Theoretically, this is the neatest option. But there are practical problems.
Embedding the version in the path (/api/v1/projects
) is the most common
solution. Django rest framework supports it.
Versions need a scheme. Do you use 1.0, 2.0, v1, v2? Or date based numbers? The latter are less emotional.
You could look at “version transformers”. Your core code would only support the latest version. A transformer should transform any old requests to the latest version (and the other way around for transforming responses). This approach makes it easier to make small changes like changing field names.
It obviously won’t work for massive changes. For that, you probably have to create an entire new API and duplicate some code.
Something to look at: tg-apicore, an add-on for django rest framework that enables jsonapi.org. It also helps with documentation generation.
There are similar projects that do the same for other standards.
Photo explanation: painting crates, building a shelf out of thick strips of paper, etc.
My name is Reinout van Rees and I program in Python, I live in the Netherlands, I cycle recumbent bikes and I have a model railway.
Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):