Course Content
FastAPI Essentials
1 sections · 32 lessons
Do clients need to support JSON schema or OpenAPI specifications to interact with your API?
What you need to know
Think of two separate things:
The wire contract (required)
- The URL, method and headers
- The JSON field names and types
- Status codes and the error body shape
- Every client depends on this
The description of it (optional)
/openapi.json,/docs,/redoc- JSON Schema for each model
- Used by tools, generators and humans
- No client needs it to make a call
A request to a FastAPI endpoint looks like this, and nothing in it mentions a schema:
curl -X POST https://api.example.com/v1/chat \ -H 'content-type: application/json' \ -d '{"prompt":"hello"}'To prove the point, here is an app with every documentation route turned off:
1from fastapi import FastAPI2from pydantic import BaseModel34app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None) # no published spec at all56class Chat(BaseModel):7 prompt: str89@app.post("/v1/chat")10def chat(body: Chat):11 return {"answer": f"echo: {body.prompt}"}Real results:
GET /docs, GET /openapi.json -> 404, 404POST /v1/chat {"prompt":"hello"} -> {'answer': 'echo: hello'}POST /v1/chat {"promt":"hello"} -> 422, loc ['body', 'prompt']The client still works, and — important — validation still happens. Turning off the spec removes the description, not the rules. The server enforces the same Pydantic model either way.
Where the spec earns its keep
- Typed clients generated for TypeScript, Kotlin or Python, so field typos become compile errors.
- Docs and try-it pages for humans.
- Gateways and contract tests that check requests and responses against it.
- LLM agents that turn operations into tool definitions.
The part clients do rely on
Clients parse your responses whether you documented them or not. That includes FastAPI's 422 detail list: once a front-end shows "field X is invalid" by reading loc, changing your error format breaks it. Treat renames, removed fields, new required fields and changed error shapes as breaking changes, and put them behind a new version such as /v2.
A real-life example
A bank's internal fraud-scoring service is called by three systems: a Java payments service, a Python batch job and a mobile backend in Go. The Java team generates a client from /openapi.json; the Python job uses plain httpx; the Go team hand-wrote a struct two years ago. All three work, because all three send the same JSON.
For security review, the bank disables /docs and /openapi.json in production and publishes the spec to an internal API catalogue during CI instead. Nothing breaks. Later, a developer renames risk_score to score. The Java build fails immediately on the regenerated client, and the contract test catches it for the others — the spec was not needed at runtime, but it made the breaking change visible before release.
Follow-up questions to expect
- "If there is no spec, how do clients know the format?" — From docs, examples or a shared SDK. The spec just makes that machine-readable and always current.
- "Can a client send extra fields?" — By default Pydantic ignores unknown fields. Set
extra="forbid"if you want typos rejected. - "How do you publish the spec without serving it?" — Call
app.openapi()in a CI script and write it to a file or registry.