Getting Started with FastAPI — Build Python REST APIs in 2026

Sanjeev SharmaSanjeev Sharma
4 min read

Advertisement

Introduction

Why This Matters

FastAPI has become the dominant Python framework for building REST APIs. It is faster than Flask in benchmarks, produces automatic OpenAPI documentation, and enforces type safety through Pydantic — all out of the box. Major companies including Microsoft, Netflix, and Uber use FastAPI in production.

For developers coming from Flask or Django REST Framework, FastAPI offers a dramatically improved developer experience: request body validation is automatic, path and query parameters are type-checked, and the interactive Swagger UI is generated for free. For new Python API developers, FastAPI is the recommended starting point in 2026.

This guide walks through building a complete CRUD API step by step, including async endpoints, Pydantic models, and dependency injection.

Installation and Setup

pip install fastapi uvicorn[standard] pydantic

Create main.py:

from fastapi import FastAPI
 
app = FastAPI(
    title="My API",
    description="A FastAPI REST API example",
    version="1.0.0",
)
 
@app.get("/")
async def root():
    return {"message": "Hello, FastAPI!"}

Run the server:

uvicorn main:app --reload

Visit http://localhost:8000/docs for interactive Swagger UI.

Path Parameters and Query Parameters

from fastapi import FastAPI, Query, Path
 
app = FastAPI()
 
@app.get("/users/{user_id}")
async def get_user(
    user_id: int = Path(..., ge=1, description="The user ID"),
    include_posts: bool = Query(False),
):
    return {"user_id": user_id, "include_posts": include_posts}
 
@app.get("/search")
async def search(
    q: str = Query(..., min_length=3, max_length=50),
    page: int = Query(1, ge=1),
    limit: int = Query(10, ge=1, le=100),
):
    return {"query": q, "page": page, "limit": limit}

Request Body with Pydantic Models

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, field_validator
from typing import Optional
 
app = FastAPI()
 
class UserCreate(BaseModel):
    name: str
    email: str
    age: Optional[int] = None
 
    @field_validator("age")
    @classmethod
    def age_must_be_positive(cls, v):
        if v is not None and v < 0:
            raise ValueError("Age must be positive")
        return v
 
class UserResponse(BaseModel):
    id: int
    name: str
    email: str
 
@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
    # In real code, save to database here
    return UserResponse(id=1, name=user.name, email=user.email)

CRUD Endpoints

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Dict
 
app = FastAPI()
 
class Item(BaseModel):
    name: str
    price: float
    in_stock: bool = True
 
# In-memory store for demonstration
items: Dict[int, Item] = {}
next_id = 1
 
@app.get("/items/{item_id}", response_model=Item)
async def get_item(item_id: int):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    return items[item_id]
 
@app.post("/items", response_model=Item, status_code=201)
async def create_item(item: Item):
    global next_id
    items[next_id] = item
    next_id += 1
    return item
 
@app.put("/items/{item_id}", response_model=Item)
async def update_item(item_id: int, item: Item):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    items[item_id] = item
    return item
 
@app.delete("/items/{item_id}", status_code=204)
async def delete_item(item_id: int):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    del items[item_id]

Dependency Injection

from fastapi import FastAPI, Depends, HTTPException, Header
 
app = FastAPI()
 
async def verify_token(authorization: str = Header(...)):
    if not authorization.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Invalid token format")
    token = authorization[7:]
    if token != "secret-token":
        raise HTTPException(status_code=401, detail="Invalid token")
    return token
 
@app.get("/protected")
async def protected_route(token: str = Depends(verify_token)):
    return {"message": "Access granted", "token": token}

Async Database with SQLAlchemy

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import DeclarativeBase, mapped_column, Mapped
from fastapi import FastAPI, Depends
 
DATABASE_URL = "postgresql+asyncpg://user:pass@localhost/db"
engine = create_async_engine(DATABASE_URL)
 
class Base(DeclarativeBase):
    pass
 
class User(Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    email: Mapped[str]
 
async def get_db():
    async with AsyncSession(engine) as session:
        yield session

Common Mistakes

  • Returning raw dicts without response_model — bypasses response validation
  • Using sync database calls inside async endpoints — blocks the event loop
  • Not setting status_code=201 on POST endpoints that create resources
  • Forgetting raise HTTPException and returning plain error dicts instead
  • Not using Depends() for shared logic — leads to code duplication

Best Practices

  • Always define response_model to control what data is returned to clients
  • Use Pydantic's field validators for business logic validation
  • Separate schemas from DB models — use separate UserCreate, UserUpdate, UserResponse
  • Use APIRouter to organize endpoints by domain (users, products, orders)
  • Add logging middleware and a global exception handler for production

Key Takeaways

  • FastAPI auto-generates Swagger UI at /docs and ReDoc at /redoc
  • Path parameters use Path(), query params use Query(), body uses Pydantic models
  • HTTPException raises HTTP errors with status codes and JSON detail messages
  • Depends() implements dependency injection for auth, DB sessions, and shared logic
  • FastAPI is fully async — use async def and async DB drivers for maximum performance
  • Pydantic v2 (used by FastAPI 0.100+) is significantly faster than Pydantic v1
  • FastAPI's type hint system catches bugs at development time, not at runtime

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading