A Django REST API in a Single File2020-10-15
I previously covered writing a Django application in a single file, for both synchronous and asynchronous use cases. This post covers the angle of creating a REST API using Django in a single file.
Undeniably, REST API’s are a very common use case for Django these days. Nearly 80% of this year’s Django community survey respondents said they use Django REST Framework (DRF). DRF is great for building API’s and provides many of the tools you’d want in a production-ready application. But for building a very small API, we can get by solely with tools built into Django itself.
Without further ado, our example application is below.
You can save it as
app.py, and run it with
python app.py runserver (tested with Django 3.1).
An explanation follows after the code:
Neat, just 73 lines, or 63 not counting imports.
The first thing we do, following imports, is to call
settings.configure() with the minimum configuration to get Django running.
I covered most of these settings in my first single-file app post which I won’t repeat too much here.
One extra thing we’re using compared to that post is
CommonMiddleware, one of Django’s many “included batteries”.
In its default configuration it will redirect URL’s not ending with a slash (“/”) to those with one, useful for getting users to their intended content.
Second, we define some static data for our API to serve, using dataclasses (new in Python 3.7). These are great for storing and serving a small amount of unchanging data. At some point we’d want to move to using a database, but for our purposes it is easier to avoid setting this up.
(I’ve also shown my bad taste by making this a Rick and Morty character API.)
Third, we define three views:
indexredirects to the character list URL, as that’s our only data type in the API. If we expanded our API, we might want to show a “front page”.
characters_listreturns a list of characters. If our list of characters grew large, we might want to paginate this to return only slices of characters at a time.
characters_detailreturns the representation of a single character. This also has an error path for when we’re given an ID that doesn’t match.
Fourth, we map URL’s to our views in the
Fifth, we create the WSGI application object, which allows us to deploy the application.
For example, if we’d saved this file as
app.py, we could run it on a production server with
Sixth, we introduce
manage.py style handling when the module is run as
This allows us to run the application with
python app.py runserver locally.
Trying It Out
Here’s a sample of using that API with httpie, a neat command-line tool for making HTTP requests.
First, hitting the index URL:
This redirects us to
/characters/ as expected.
Fetching that, we see the JSON dat for both characters:
We might try fetching Morty’s page:
Aha! We didn’t add the trailing slash, so our request has been redirected. Fetching the complete URL, we see Morty’s data:
These days I can’t write a blog post without mentioning testing. We can use Django’s built-in test framework to write some quick tests that cover all our endpoints.
Save this code in a file called
tests.py, in the same folder as the application:
These tests use Django’s test client to make requests and then assert on the response status code and content.
Because we don’t have a database, the tests can inherit from the faster
SimpleTestCase, rather than using
TestCase which adds some database management.
We can run these tests using
app.py like so:
I hope this has helped you figure out a way into building small API’s with Django. If your API takes off, do check out Django REST Framework!
For a longer tutorial that uses the database, check out Curtis Maloney’s post.
Want better tests? Check out my book Speed Up Your Django Tests which teaches you to write faster, more accurate tests.
One summary email a week, no spam, I pinky promise.
© 2021 All rights reserved.