Creating Solid APIs

23 May 20183 min read

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 .

The slides:

Video on YouTube:


  • 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.


  • 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)


  • 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.


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


Title photo by Matt Zhou on Unsplash

tags: API, Django, Python, Talk