FastAPI is a modern Python web framework built for APIs. It uses standard type hints to validate request and response data, and it generates OpenAPI (Swagger) documentation automatically. If you are building a REST or HTTP API and want clear contracts, good performance, and optional async support, FastAPI is a strong choice. You should be comfortable with functions, data types, and ideally type hints and JSON.

1. Why FastAPI for APIs

FastAPI is designed for API development: you define endpoints with type hints and Pydantic models, and the framework handles validation, serialisation, and docs. It is asynchronous by default (you can use async def for I/O‑bound routes) and is one of the fastest Python frameworks in benchmarks. For a full web app with server‑rendered HTML and an admin, Django may fit better; for a minimal HTTP API with few dependencies, Flask is an option. FastAPI sits in between: minimal boilerplate, strong typing, and built‑in OpenAPI and ReDoc.

2. Install FastAPI and uvicorn

Use a virtual environment, then install FastAPI and uvicorn (the ASGI server used to run FastAPI apps):

python -m venv .venv
# Activate: .venv\Scripts\activate (Windows) or source .venv/bin/activate (macOS/Linux)

pip install fastapi uvicorn

Uvicorn is the server that runs your FastAPI app in development and often in production behind a reverse proxy.

3. Minimal application

Create a file main.py (or app.py):

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/items/{item_id}")
def read_item(item_id: int):
    return {"item_id": item_id}

FastAPI() creates the app. @app.get("/") registers a GET handler for the root. The return value is automatically serialised to JSON. The item_id: int in read_item is a path parameter: FastAPI validates that the segment is an integer and converts it; invalid values yield a 422 response with a clear error body.

4. Run the server

From the directory that contains main.py:

uvicorn main:app --reload

main is the module name (the file main.py), and app is the variable holding the FastAPI() instance. Open http://127.0.0.1:8000/ in your browser for the root response. Use --reload only in development so the server restarts when you change code. For production, run without --reload and typically behind Nginx or similar.

5. Interactive documentation

FastAPI exposes two documentation UIs by default:

  • Swagger UI: http://127.0.0.1:8000/docs — try endpoints and see request/response schemas.
  • ReDoc: http://127.0.0.1:8000/redoc — read‑friendly API docs.

Both are generated from your route signatures and Pydantic models. No extra configuration is required; this is very helpful when you work with front‑end developers or when you call your own API from requests or JavaScript.

6. Path and query parameters

Path parameters are part of the URL path; query parameters come after ?. FastAPI infers them from your function signature:

from typing import Optional

@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}

@app.get("/items/")
def read_items(skip: int = 0, limit: int = 10, q: Optional[str] = None):
    return {"skip": skip, "limit": limit, "q": q}

# Example: GET /items/?skip=0&limit=20&q=python

Parameters with default values are treated as query parameters. Use Optional[T] or T | None for optional query args. Invalid types (e.g. a non‑integer for user_id) result in 422 with a JSON error description.

7. Request body with Pydantic

For POST/PUT bodies, define a Pydantic model. FastAPI validates the incoming JSON and parses it into your model:

from pydantic import BaseModel
from typing import Optional

class Item(BaseModel):
    name: str
    price: float
    description: Optional[str] = None

@app.post("/items/")
def create_item(item: Item):
    return item

When the client sends {"name": "Widget", "price": 9.99}, FastAPI builds an Item instance. Missing required fields or wrong types produce 422 validation errors. The returned item is again serialised to JSON. This matches how many REST APIs work; see read and write JSON for Python–JSON mapping.

8. Response model and status codes

You can declare a response_model so the response shape is documented and validated. Use status_code to return non‑200 when appropriate:

from fastapi import status

class User(BaseModel):
    id: int
    name: str
    email: str

@app.get("/users/{user_id}", response_model=User)
def get_user(user_id: int):
    return User(id=user_id, name="Alice", email="[email protected]")

@app.post("/users/", status_code=status.HTTP_201_CREATED)
def create_user(user: User):
    # Save user, then return it or an id
    return user

For errors, raise HTTPException(status_code=404, detail="Not found") so FastAPI returns the right status and body.

9. Async endpoints

FastAPI supports async route handlers. Use async def when you do I/O (database, HTTP calls) so the server can handle other requests while waiting:

@app.get("/data")
async def fetch_data():
    # Simulate I/O (in real code: await db.query(...) or await httpx.get(...))
    return {"status": "ok"}

You can mix sync and async routes. Use async only where you actually benefit (I/O); CPU‑bound work is better off in a thread pool or task queue. For more on async in Python, see async and await.

10. Organising larger apps with routers

As the app grows, split routes into routers (similar to Flask blueprints):

# routers/items.py
from fastapi import APIRouter
router = APIRouter(prefix="/items", tags=["items"])

@router.get("/")
def list_items():
    return []

@router.get("/{item_id}")
def get_item(item_id: int):
    return {"item_id": item_id}

# main.py
from fastapi import FastAPI
from .routers import items
app = FastAPI()
app.include_router(items.router)

Routers keep related endpoints together and make the OpenAPI docs easier to navigate.

11. Common issues and next steps

If you get ModuleNotFoundError, run uvicorn from the project root and use the correct module path (e.g. uvicorn main:app for main.py). For validation errors, check the 422 response body: it lists which fields failed. Use the /docs page to see the exact schema your API expects.

From here: add a database (e.g. SQLAlchemy with SQLite), add auth (JWT or OAuth2), and read the official FastAPI tutorial. For comparison with other frameworks, see Django and Flask.