DRF: Consuming the API
Four lessons have built up TaskFlow's API from the inside — serializers, viewsets, permissions, filtering. This last DRF lesson looks at it from the other side: what it actually looks like for something outside Django entirely to call that API and use what comes back.
DRF's Browsable API
One of DRF's nicer touches, and something that requires zero extra setup: visiting an API endpoint
directly in a regular web browser doesn't just dump raw JSON at you. DRF detects that the request
came from a browser and renders a clean, human-friendly HTML page instead — showing the JSON nicely
formatted, along with forms for trying a POST or PUT right there in the
page, and links for paging through results. Visiting /api/tasks/ in a browser during
development is a genuinely fast way to sanity-check an endpoint without reaching for a separate tool
at all — it comes from DRF automatically the moment a ViewSet or APIView
is wired up, with nothing extra to configure.
Calling the API With curl
A plain GET request needs nothing special — no session, no cookie, since the endpoint
is read-only for anonymous requests under the IsAuthenticatedOrReadOnly permission from
the previous lesson:
curl http://localhost:8000/api/tasks/
Creating a task requires a valid token, sent in the same Authorization header covered
in DRF: Authentication & Permissions, along with a
JSON body describing the new task:
curl -X POST http://localhost:8000/api/tasks/ \
-H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4" \
-H "Content-Type: application/json" \
-d '{"title": "Draft the release notes", "due_date": "2026-09-01", "priority": "medium"}'
-H attaches each header, and -d supplies the request body — this single
command reaches TaskFlow's API exactly as a real client would, with no browser involved at all.
Calling the API From Python With requests
curl is great for a quick check; a real client is usually code. Python's
requests library is a natural way to call TaskFlow's API from a completely separate
script — this is exactly the shape any automation, data pipeline, or integration script would take:
# A separate script, entirely outside the Django project
import requests
headers = {'Authorization': 'Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4'}
response = requests.get('http://localhost:8000/api/tasks/', headers=headers)
data = response.json()
print(data['count'], 'tasks total')
for task in data['results']:
print(task['title'], task['priority'])
# Creating a task follows the same shape as the curl example above
new_task = {'title': 'Draft the release notes', 'due_date': '2026-09-01', 'priority': 'medium'}
response = requests.post('http://localhost:8000/api/tasks/', json=new_task, headers=headers)
print(response.status_code, response.json())
Notice response.json() parses the paginated body from the previous lesson straight
back into a Python dict — data['count'] and data['results'] work exactly
like the JSON keys shown there. There's nothing Django-specific about this script at all; it would
run identically against any server speaking the same API.
The Same Idea, From a Real Frontend
A separate JavaScript frontend — React, Vue, or a mobile app — talks to a Django backend exactly
this way: it sends HTTP requests with fetch or axios instead of Python's
requests, but the API itself, the tokens, the JSON shapes, and the pagination and
filtering behavior are all identical from the server's point of view. This is the essence of a
headless architecture — Django never renders a template at all here, it's purely a
JSON API, and something else entirely owns the user interface. This site's own React Native track
covers the client-side half of exactly this pattern, in its coverage of fetch and
axios — everything built across these five DRF lessons is what a screen in that track
would ultimately be calling.
Documenting the API: OpenAPI/Swagger
An API with a couple of endpoints is easy to remember by heart; one with dozens quickly isn't.
Packages like drf-spectacular and drf-yasg generate an
OpenAPI (formerly known as Swagger) schema automatically, straight from a project's
existing serializers and views — no separate documentation to write and keep in sync by hand. The
result is an interactive page listing every endpoint, its expected request body, and its possible
responses, that other developers (or a future you) can browse without reading the view code
directly. This is conceptual awareness worth having going in: it's not something TaskFlow needs with
just a handful of endpoints, but it becomes genuinely valuable the moment an API grows past what one
person can hold in their head.
curl and requests commands above are
correct examples of calling a real DRF API — but this website's own project doesn't run a live Django
server, so none of these requests actually go anywhere from this page.