FastAPI Essentials

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:

Bash
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:

Python
from fastapi import FastAPIfrom pydantic import BaseModelapp = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)   # no published spec at allclass Chat(BaseModel):    prompt: str@app.post("/v1/chat")def chat(body: Chat):    return {"answer": f"echo: {body.prompt}"}

Real results:

Text
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.