What Is FastAPI? Modern Python APIs Explained
A clear introduction to FastAPI — ASGI and Starlette, Pydantic-driven validation, automatic OpenAPI docs, async support, and how it compares to Flask and Django.
What you'll learn
- ✓What FastAPI is and where it sits in the Python web ecosystem
- ✓How ASGI and Starlette make async-first APIs possible
- ✓How type hints plus Pydantic give you validation almost for free
- ✓Why automatic OpenAPI / Swagger docs change how teams collaborate
- ✓How FastAPI compares to Flask and Django, and when to pick each
Prerequisites
- •A basic understanding of Python — see What Is Python?
- •Comfort opening a terminal and running pip
FastAPI is the most popular Python framework for building HTTP APIs — the kind of backend services that power mobile apps, single-page web apps, and machine-learning models in production. Released in late 2018, it has become a default choice across startups, research labs, and large tech companies.
This post explains what FastAPI is, the design decisions that make it productive, and when it’s the right tool for the job.
If Python is new to you, start there first.
What FastAPI actually is
FastAPI is a Python web framework focused on building APIs that return JSON. Three concrete pieces define it:
- Starlette — a lightweight ASGI web framework that handles routing, requests, responses, websockets, and middleware. FastAPI is built directly on top of it.
- Pydantic — a data validation library that turns Python type hints into runtime checks. FastAPI uses Pydantic for everything: request bodies, query parameters, response models.
- A small but opinionated layer on top that wires those two together and generates documentation automatically.
The result is a framework where, in many cases, the type hints you’d write anyway are the validation, are the documentation, and are the API contract.
ASGI and async, briefly
Older Python web frameworks like Flask and Django were built on WSGI, a synchronous interface. Each request blocks a worker until it finishes — which is fine for fast endpoints but wasteful when you’re waiting on slow I/O, external APIs, or LLM calls.
ASGI is the asynchronous successor: a server can hold thousands of in-flight requests with async/await, releasing the worker any time it’s waiting on I/O. FastAPI is async-first, which makes it well-suited to modern workloads — gateways to AI models, websocket-heavy apps, services that fan out to many backends.
You can still write plain synchronous handlers in FastAPI; it’ll run them on a worker thread automatically. Mix and match as the task demands.
Type hints become validation
This is the trick that makes FastAPI feel different from older frameworks. You write a function with normal Python type hints, and FastAPI reads them to figure out the API contract.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "q": q}
What this gives you, for free:
item_idmust be an integer. If a client sends/items/abc, FastAPI returns a clear422 Unprocessable Entityresponse automatically.qis an optional query parameter. Open/items/42?q=helloand it appears in the response.- The OpenAPI schema documents the types and example values exactly.
Add a request body and the magic gets more pronounced:
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
in_stock: bool = True
@app.post("/items")
def create_item(item: Item):
return {"created": item.name, "price": item.price}
When a client POSTs JSON, Pydantic validates it against the Item model. If a required field is missing, or price is a string instead of a number, the client receives a precise error message telling them what went wrong. You wrote zero validation code.
Automatic OpenAPI docs
Every FastAPI app exposes two interactive documentation pages out of the box:
/docs— Swagger UI, where developers can read, try, and execute every endpoint from the browser./redoc— a polished reference doc generated from the same OpenAPI schema.
This is a bigger deal than it sounds. Most API teams spend significant effort keeping documentation in sync with code. With FastAPI, the docs are the code — there is no second source of truth to drift. A frontend developer can hit /docs, see exactly which endpoints exist and what they expect, and even try them right there. New backend engineers onboard much faster.
The same OpenAPI schema also feeds client-code generators in TypeScript, Go, Rust, and others. A typed API client falls out of the framework with no extra work.
FastAPI vs Flask vs Django
A quick honest comparison.
Flask
Flask is the venerable minimalist micro-framework. It’s small, well-understood, and beloved for prototypes and small services. Its weaknesses relative to FastAPI:
- Validation is your problem (or you pull in extra libraries).
- Documentation is your problem.
- Async support exists but feels bolted on.
If you have a long-standing Flask codebase, there is no urgent reason to migrate. For greenfield API work, FastAPI almost always wins on developer experience.
Django
Django is the heavyweight “batteries-included” framework: an ORM, an admin panel, authentication, sessions, templates, forms — the whole stack. Combined with Django REST Framework, it powers a large fraction of Python-based APIs.
When Django is the right choice:
- You’re building a full web product with server-rendered HTML, an admin interface, and complex data models.
- You want an opinionated, well-trodden stack with answers to every architectural question.
When FastAPI is the right choice:
- You’re building a pure API that’s consumed by a frontend (React, mobile, etc.).
- You care about async I/O — talking to LLMs, websockets, heavy fan-out.
- You’d rather pick your own ORM, auth, and so on, à la carte.
A common pattern at large companies: Django for the admin and internal tooling, FastAPI for public APIs and ML-serving endpoints.
A first FastAPI program
A complete working example, end to end.
Install:
pip install "fastapi[standard]"
The [standard] extra pulls in uvicorn (the ASGI server) and a few other niceties.
Write main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/hello")
def hello(name: str = "world"):
return {"message": f"Hello, {name}!"}
Run it:
fastapi dev main.py
Open http://127.0.0.1:8000/hello and you’ll see:
{"message": "Hello, world!"}
Try http://127.0.0.1:8000/hello?name=Ada and the response changes to Hello, Ada!. Now open http://127.0.0.1:8000/docs — there is a fully interactive Swagger page for the endpoint you just wrote. Nothing else to configure.
Try it yourself. Extend the example above by adding a POST endpoint that accepts a JSON body.
from pydantic import BaseModel
class Greeting(BaseModel):
name: str
excited: bool = False
@app.post("/greet")
def greet(g: Greeting):
message = f"Hello, {g.name}"
if g.excited:
message += "!!!"
return {"message": message}Restart the server, open /docs, and use the Swagger UI to send a JSON body. Then try sending an invalid one — for example, { "name": 42 }. Notice the structured 422 response. You wrote no validation code; Pydantic and FastAPI handled it.
When FastAPI is the right tool
Strong fits:
- REST or RPC-style APIs consumed by web or mobile frontends.
- LLM and ML inference services. The async model handles long-running model calls and streaming responses well; the Python ecosystem is where the models live.
- Microservices in a polyglot stack — small, focused services with clear contracts.
- Internal tooling APIs where automatic documentation reduces friction.
When it’s not the best fit
- Server-rendered web apps with templates, admin panels, and form-heavy workflows — Django is still better.
- CPU-heavy work that doesn’t move data over the network. Async doesn’t help with CPU; a different runtime or worker model fits better.
- Pure batch jobs and scripts. A framework is overkill; write a normal Python program.
- Teams that need to ship without ever learning type hints. FastAPI’s value comes from leaning on them. If you resist on principle, you’ll fight the framework.
How FastAPI fits with the rest of the stack
A typical modern Python service:
- FastAPI on top of Uvicorn (a fast ASGI server)
- A SQL database accessed via SQLAlchemy 2.0 or an async ORM like Tortoise / SQLModel
- Pydantic for request/response models — same library FastAPI already uses
- Background tasks via Celery, RQ, or
asyncio.create_taskfor short-lived ones - Containerised with Docker and deployed to any cloud provider
On the frontend side, FastAPI is happy talking to React, Astro, Vue, mobile apps, other services, or a simple HTML page rendered elsewhere.
What FastAPI is not
- Not a full-stack framework. It does not render HTML templates by default (though it can, via Jinja2). It is an API framework first.
- Not magic. Validation comes from Pydantic, the server from Uvicorn, async from Python itself. FastAPI is the (excellent) integration layer.
- Not the only async Python framework. Litestar, Sanic, BlackSheep, and Starlette itself are all reasonable choices. FastAPI is simply the most popular and the best documented.
Recap
You now know:
- FastAPI is an async-first Python framework for building APIs
- It rests on Starlette (ASGI) and Pydantic (type-driven validation)
- Type hints become validation, serialisation, and automatic OpenAPI docs
- Compared to Flask it is more featureful and modern; compared to Django it is leaner and API-focused
- Use it for APIs, LLM/ML services, and microservices; use Django for full server-rendered web products
Next steps
The natural follow-up is connecting FastAPI to a real database, adding authentication, and deploying it. Until then, the official tutorial is genuinely excellent — work through it in an afternoon and you’ll be productive.
Related: What Is Python?, What Is SQL?, What Is Docker?.
Questions or feedback? Email codeloomdevv@gmail.com.