Course Content
FastAPI Essentials
1 sections · 32 lessons
How does FastAPI leverage type hints for automatic API documentation?
What you need to know
- Inspect — FastAPI reads each route's parameters and annotations using Python's
inspectandtypingtools. - Classify — each parameter is marked as path, query, header, cookie or body.
- Build schemas — Pydantic generates a JSON Schema for every model and constrained type.
- Assemble — FastAPI combines paths, schemas, tags and summaries into one OpenAPI 3.1 document.
- Serve —
/openapi.jsonreturns it;/docsand/redocrender it.
Here is a reranking endpoint from a retrieval service:
1from typing import Annotated2from fastapi import FastAPI, Query3from pydantic import BaseModel, Field45app = FastAPI(title="Retrieval API", version="1.2.0")67class RerankIn(BaseModel):8 passages: list[str] = Field(min_length=1, description="Candidate chunks from the vector store")910class RerankOut(BaseModel):11 order: list[int]12 scores: list[float]1314@app.post("/rerank", tags=["retrieval"], summary="Rerank candidate passages")15def rerank(q: Annotated[str, Query(min_length=3, description="The user's question")],16 body: RerankIn) -> RerankOut:17 ...Parts of what app.openapi() really produces:
openapi: 3.1.0parameters: [{"name": "q", "in": "query", "required": true, "schema": {"type": "string", "minLength": 3, ...}}]responses: ['200', '422']200 schema: {'$ref': '#/components/schemas/RerankOut'}RerankIn: {'passages': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1, 'description': 'Candidate chunks from the vector store'}}Every detail came from the code: q is a required query parameter because it has no default; minLength: 3 came from Query(min_length=3); the 422 response was added because the route has validation; the 200 schema came from the -> RerankOut return type.
Making the docs richer
- A docstring on the function becomes the endpoint description.
Field(description=..., examples=[...])documents single fields.tags=[...]groups endpoints in the UI.responses={404: {"description": "Index not found"}}documents extra error codes.
To hide the docs on a private service, use FastAPI(docs_url=None, redoc_url=None, openapi_url=None).
A real-life example
A retrieval team builds the rerank service above. The front-end team and an internal agents team both call it. Instead of a shared document, both generate typed clients from /openapi.json (for example with openapi-typescript).
When the retrieval team adds top_k: int = Query(10, le=50), the new parameter and its limit appear in the spec on the next deploy. The front-end build regenerates its client, and the compiler shows every place that should pass top_k. The agents team turns the same schema into a tool definition for the LLM. One set of type hints feeds validation, docs, two clients and an agent tool.
Follow-up questions to expect
- "What if a route has no return type?" — The 200 response schema is empty (
{}), so consumers learn nothing about the output. Add a return type orresponse_model. - "How do you add examples to the docs?" —
Field(examples=[...])on a field, ormodel_config = {"json_schema_extra": {"examples": [...]}}on the model. - "Can you customise the whole schema?" — Yes, by overriding
app.openapiwith a function that edits the generated dict. FastAPI builds the schema once and caches it.