FastAPI is a modern Python web framework for building APIs. It is fast, uses Python type hints for validation, and generates interactive API documentation automatically. It is a favourite for AI and data backends because it fits naturally with the Python ecosystem.
Install
python -m venv .venv
# Windows: .venv\Scripts\activate | macOS/Linux: source .venv/bin/activate
pip install "fastapi[standard]"Step 1: A first endpoint
Create main.py:
from fastapi import FastAPI
app = FastAPI(title="Course API")
@app.get("/")
def home():
return {"message": "Hello from FastAPI"}Run it:
fastapi dev main.pyOpen http://127.0.0.1:8000/docs to see the Swagger UI. You can call every endpoint from the browser.
Step 2: Define the data model with Pydantic
from pydantic import BaseModel, Field
class CourseIn(BaseModel):
title: str = Field(min_length=3, max_length=100)
duration_weeks: int = Field(ge=1, le=52)
online: bool = True
class Course(CourseIn):
id: intIf a request sends duration_weeks: 0 or a missing title, FastAPI rejects it with a clear 422 error before your code runs.
Step 3: CRUD endpoints
An in-memory dictionary keeps the example simple. In a real app you would use a database with SQLAlchemy or SQLModel.
from fastapi import FastAPI, HTTPException, status
app = FastAPI(title="Course API")
db: dict[int, Course] = {}
next_id = 1
@app.get("/courses", response_model=list[Course])
def list_courses():
return list(db.values())
@app.get("/courses/{course_id}", response_model=Course)
def get_course(course_id: int):
if course_id not in db:
raise HTTPException(status_code=404, detail="Course not found")
return db[course_id]
@app.post("/courses", response_model=Course, status_code=status.HTTP_201_CREATED)
def create_course(data: CourseIn):
global next_id
course = Course(id=next_id, **data.model_dump())
db[next_id] = course
next_id += 1
return course
@app.put("/courses/{course_id}", response_model=Course)
def update_course(course_id: int, data: CourseIn):
if course_id not in db:
raise HTTPException(status_code=404, detail="Course not found")
db[course_id] = Course(id=course_id, **data.model_dump())
return db[course_id]
@app.delete("/courses/{course_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_course(course_id: int):
if db.pop(course_id, None) is None:
raise HTTPException(status_code=404, detail="Course not found")Step 4: Query parameters
Function parameters that are not in the path become query parameters automatically.
@app.get("/search", response_model=list[Course])
def search(q: str, online: bool | None = None):
result = [c for c in db.values() if q.lower() in c.title.lower()]
if online is not None:
result = [c for c in result if c.online == online]
return resultGET /search?q=python&online=true now works, with types converted and validated.
FastAPI vs Django vs Flask
| FastAPI | Django | Flask | |
|---|---|---|---|
| Best for | APIs, AI/ML backends | Full websites with admin | Small, flexible apps |
| Validation | Built-in (Pydantic) | Forms / DRF serializers | Add a library |
| Async | Native | Supported | Limited |
| Auto API docs | Yes | With DRF add-ons | Add a library |
Interview questions
- Why is FastAPI fast? It runs on ASGI (Starlette + Uvicorn) and supports
asyncendpoints, so one process handles many concurrent requests. - What does `response_model` do? It validates and filters the output, so you never leak fields you did not intend to return.
- 422 vs 400? FastAPI returns 422 Unprocessable Entity when the request body or parameters fail validation.
Next steps
Connect a PostgreSQL database with SQLModel, add JWT login, and build a React frontend. The complete stack is covered in the Python Full Stack + AI course.
