Increasingly, our apps are used not by humans but by other apps — via their APIs. Thus it is increasingly important that your APIs are well-designed and easy to consume for other developers. I will share tips and good practices on authentication, versioning, documentation, response structure, and why it all matters.
I have given this talk at PyCon LT 2018, DjangoCon Europe 2018, EuroPython 2018, DjangoCon Australia 2018, and PyCon Estonia 2018 .
Intro
- Our applications are increasingly being used not by humans but by other applications — via their APIs.
- APIs however are first used by humans — the other developers.
- Thus your APIs must even more importantly target humans as well.
- APIs are user interface for developers — you should make that UI as good as possible.
Documentation
- Docs give the first impression, could mean difference between your API (or package) being chosen or not.
- They take effort and can be sort of boring, but it’s actually worth it.
- I want to know how to access the API, get started quickly, what the common errors are, how pagination works, etc.
- For the endpoints, provide the URLs and operations (list, read, update, etc), request/response format, optional parameters, permissions, etc.
- Ensure your docs are up-to-date by autogenerating it. Common choices are OpenAPI, Swagger, etc, but find out what your tooling (e.g. Django REST Framework) supports!
- You could also generate client libraries from your API code/schema.
Standards & JSON API
- Using common standards is extremely helpful.
- They bring familiarity and make getting started easier as users can apply existing knowledge.
- They also help avoid common pitfalls. Think Django making secure password storage easy.
- JSON API is my current standard of choice.
There are others such as GraphQL. Just pick one.
- All API responses (including errors) have standardized structure.
- They can also include other, related resources. Think
.select_related()
in Django. Saves network requests. - Pagination, filtering, ordering are also standardized to some extent.
- For special cases, like lots of data, you can include link to the raw data in the response, and send the raw data out-of-band.
Authentication & Authorization
- Token authentication — client acquires a token (eg via user login), then sends it with each request.
- Good fit for e.g. native mobile apps.
- DRF has it built-in.
- Session authentication is very similar.
- OAuth2 standard
- For creating platforms, ala Facebook.
- Covers many usecases & flows
- Many packages available, eg DjangoOAuth Toolkit and OAuthLib (lower level)
Versioning
- You should have versioning from Day One.
- Header-based versioning is more idealistic, but can be problematic in real world.
- Path-based is often more pragmatic. Also, your server logs will magically contain the request versions.
- For version identifiers, can use integers (
v1
) or dates (2018-05-23
). I prefer dates. - Make it easy for developers to find out about changes!
- On the server side, version transformers help — see the Stripe blog post for more info.
tg-apicore
- Our implementation of some of of the ideas here
- https://github.com/thorgate/tg-apicore
Client perspective
- Looking at how to use AWS and GCP APIs, using speech recognition as example.
- Both have good, comprehensive docs, code to get started, etc.
- Both are also quite similar to each other, making use of familiar patterns
In Summary
- Invest in documentation
- Embrace standards
- Use automation
- Reduce friction
References
- Another summary by Reinout van Rees
- Documenting your API — Django REST framework
- How to make a good library API — Flávio Juvenal
- OAuth 2.0 Servers