Skip to content

All lessons

Area 08 // BackendLesson 126 / 14015 min read

REST APIs with FastAPI

A REST API exposes your app's data and actions as resources at URLs that clients use with standard HTTP methods, and FastAPI is a popular Python framework for building them quickly, with request validation and interactive OpenAPI documentation generated from your code.

Think of it like this

Analogy

A well-run library: every book has a shelf address (a URL), and there are a few standard actions anyone understands: borrow (GET), donate (POST), replace a copy (PUT), fix a page (PATCH), withdraw (DELETE). The catalogue at the entrance describes every shelf and rule (the OpenAPI docs). Visitors don't need to learn special procedures for each book.

The problem it solves

Your RAG app, agent or chatbot needs a backend that web apps, mobile apps, other services and AI agents can call. Ad-hoc endpoints like /doStuff?mode=3 are hard to use, document and secure. REST conventions make APIs predictable, and FastAPI removes most of the boilerplate: parsing, validation, errors and docs.

How it works: REST APIs

  1. Resources are nouns: /documents, /documents/{id}, /conversations/{id}/messages.
  2. Methods are verbs: GET list or read, POST create (or run an action like /ask), PUT replace, PATCH partially update, DELETE remove.
  3. JSON bodies in and out; consistent field names.
  4. Status codes that mean what they say (HTTP).
  5. Stateless requests: each carries what's needed (auth token, parameters); server-side state lives in databases (databases).
  6. Lists are paginated (pagination); filters go in query parameters (?status=open).
  7. Version the API (/v1) and avoid breaking changes within a version.
  8. AI endpoints often aren't pure CRUD: POST /ask or POST /chat runs an action; long ones return a job (async jobs); streaming ones use SSE.

How it works: building an API with FastAPI

  1. Create the app: app = FastAPI(title=..., version=...).
  2. Declare data models with Pydantic (validation): input models and output models.
  3. Write path operations: @app.post("/documents", status_code=201, response_model=Doc) on a normal (or async) function.
  4. Path and query parameters come from function arguments with type hints (doc_id: int).
  5. Dependencies (Depends) inject shared things: database sessions, the current user (auth), the LLM client (swappable in tests).
  6. Errors: raise HTTPException(404, "not found").
  7. Run it: uvicorn app:app --reload locally; in production behind a process manager or container (Docker).

How it works: API docs with OpenAPI

  1. FastAPI generates an OpenAPI document at /openapi.json from your routes and models.
  2. Interactive docs at /docs (Swagger UI) and /redoc let you try requests in the browser.
  3. Add descriptions, examples and response codes so the docs are useful.
  4. Generate clients (TypeScript, Python) from the spec; agents and tools can also read it to call your API.
  5. Keep it accurate by testing that the spec matches behaviour.

See it in code

Install
pip install fastapi httpx
Needs
Python 3.10+. Run it for real with: pip install uvicorn, then uvicorn file:app --reload, and open /docs.

A small CRUD API for documents, exercised with the test client, plus the OpenAPI paths it generates.

documents_api.py
from fastapi import FastAPI, HTTPException
from fastapi.testclient import TestClient
from pydantic import BaseModel
 
app = FastAPI(title="Documents API", version="1.0")
 
class DocIn(BaseModel):
    title: str
    text: str
 
class Doc(DocIn):
    id: int
 
DB: dict[int, Doc] = {}
 
@app.post("/documents", status_code=201, response_model=Doc)       # create
def create(doc: DocIn):
    new = Doc(id=len(DB) + 1, **doc.model_dump())
    DB[new.id] = new
    return new
 
@app.get("/documents", response_model=list[Doc])                    # list
def list_docs():
    return list(DB.values())
 
@app.get("/documents/{doc_id}", response_model=Doc)                 # read one
def read(doc_id: int):
    if doc_id not in DB:
        raise HTTPException(404, "document not found")
    return DB[doc_id]
 
@app.delete("/documents/{doc_id}", status_code=204)                 # delete
def delete(doc_id: int):
    DB.pop(doc_id, None)
 
c = TestClient(app)
print(c.post("/documents", json={"title": "Leave", "text": "25 days"}).status_code, "created")
print(c.post("/documents", json={"title": "Expenses", "text": "Meals 40/day"}).json())
print(c.get("/documents").status_code, [d["title"] for d in c.get("/documents").json()])
print(c.delete("/documents/1").status_code, "deleted")
print(c.get("/documents/1").status_code, c.get("/documents/1").json())
spec = c.get("/openapi.json").json()                                # generated automatically
print("OpenAPI paths:", {p: sorted(ops) for p, ops in spec["paths"].items()})
Output
201 created
{'title': 'Expenses', 'text': 'Meals 40/day', 'id': 2}
200 ['Leave', 'Expenses']
204 deleted
404 {'detail': 'document not found'}
OpenAPI paths: {'/documents': ['get', 'post'], '/documents/{doc_id}': ['delete', 'get']}

The in-memory dict stands in for a database. The capstone RAG app is built the same way, with GET /health, GET /ready and POST /ask.

A real example

Example

An API that agents can use too

A team exposed their knowledge base through a FastAPI service: GET /v1/articles?query=..., GET /v1/articles/{id}, POST /v1/answers. Because the OpenAPI spec had clear descriptions and examples, the frontend team generated a typed TypeScript client in minutes, and later the same spec was wrapped as tools for an internal agent (MCP) with almost no extra code. When they needed a breaking change to the answer format, they added /v2/answers and kept /v1 running for six months.

The easy way

Start here

Start with FastAPI, one Pydantic model per request and response, HTTPException for errors, and the auto-generated /docs page as your documentation and test console.

When you grow: the production setup

Production APIs add versioning, authentication dependencies, consistent error formats, pagination and filtering conventions, rate limiting, request IDs and structured logs, OpenAPI linting and contract tests, generated clients, and deployment behind a load balancer with health checks.

Trade-offs

What you gain

  • Predictable, widely understood interface.
  • FastAPI gives validation and docs for free.
  • Easy to call from any language, tool or agent.

What it costs you

  • Some AI actions don't fit CRUD neatly.
  • Chatty clients may need many requests (GraphQL or batch endpoints can help).
  • Versioning and backward compatibility take discipline.

When not to use it

  • Real-time two-way interaction (voice, collaborative editing) suits WebSockets better than plain REST.

Common mistakes

  • Verbs in URLs (/getDocuments) and everything as POST.
  • Returning database models directly, leaking internal fields.
  • No pagination on list endpoints.
  • Breaking response formats without a new version.
  • Leaving /docs publicly open for internal-only APIs without auth.

Interview questions

Try answering out loud first, then open the model answer.

What makes an API RESTful?

Model answer

Resources identified by URLs, standard HTTP methods with their usual meanings, stateless requests, standard status codes, representations such as JSON, and use of HTTP features like caching headers. In practice: noun-based paths, consistent JSON, correct codes, pagination and versioning.

Why is FastAPI popular for AI backends?

Model answer

It's Python (where AI libraries live), async-capable for many concurrent I/O-bound LLM calls, uses type hints and Pydantic for automatic validation and serialisation, generates OpenAPI docs, has a simple dependency-injection system, and performs well.

How would you design the API for a RAG chatbot?

Model answer

Resources for conversations and messages (POST /v1/conversations, GET /v1/conversations/{id}, POST /v1/conversations/{id}/messages which streams the answer over SSE), documents (POST /v1/documents returning a job ID for ingestion, GET /v1/documents?cursor=), and health endpoints; authentication on every route, rate limits per user, consistent errors, and an OpenAPI spec.

Quiz

Pick an answer to see whether it’s right and why.

  1. 01Which URL and method follow REST style for deleting document 42?
  2. 02What does FastAPI use type hints for?
  3. 03What is OpenAPI?
  4. 04What status code should DELETE return when there's nothing to send back?
  5. 05Why version an API (e.g. /v1/)?

0 of 5 answered

Key terms

REST API
An API that exposes resources at URLs and uses standard HTTP methods and status codes to work with them.
Endpoint
One URL and method in an API that does a specific job, such as POST /ask.
FastAPI
A popular Python web framework for building APIs, using type hints and Pydantic for validation and automatic docs.
OpenAPI
A standard, machine-readable description of an HTTP API's endpoints, inputs and outputs, used to generate docs, clients and tests. FastAPI produces it automatically.
CRUD
Create, Read, Update and Delete, the four basic operations on stored data, usually mapped to POST, GET, PUT or PATCH, and DELETE.

Before and after

Progress is saved in this browser only.