🎁 New User? Get 20% off your first purchase with code NEWUSER20 Register Now β†’
Menu

Categories

FastAPI Tutorial: Building Modern REST APIs with Python in 2026

FastAPI Tutorial: Building Modern REST APIs with Python in 2026

FastAPI is the fastest-growing Python web framework, designed for building APIs with Python type hints. It offers automatic documentation, data validation, and exceptional performance. This tutorial takes you from basics to a production-ready API.

Why FastAPI?

  • Performance: One of the fastest Python frameworks (on par with Node.js and Go)
  • Type safety: Automatic validation using Python type hints
  • Auto documentation: Swagger UI and ReDoc generated automatically
  • Async support: Built on ASGI with native async/await
  • Standards-based: OpenAPI and JSON Schema

Getting Started

pip install fastapi uvicorn sqlalchemy pydantic

# main.py
from fastapi import FastAPI

app = FastAPI(title="My API", version="1.0.0")

@app.get("/")
async def root():
    return {"message": "Hello, World!"}

@app.get("/items/{item_id}")
async def get_item(item_id: int, q: str = None):
    return {"item_id": item_id, "query": q}

# Run: uvicorn main:app --reload

Request Validation with Pydantic

from pydantic import BaseModel, EmailStr, Field
from typing import Optional

class UserCreate(BaseModel):
    username: str = Field(..., min_length=3, max_length=50)
    email: EmailStr
    password: str = Field(..., min_length=8)
    full_name: Optional[str] = None

class UserResponse(BaseModel):
    id: int
    username: str
    email: str
    full_name: Optional[str]
    
    class Config:
        from_attributes = True

@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
    # Pydantic automatically validates the request body
    db_user = crud.create_user(db, user)
    return db_user

Database Integration with SQLAlchemy

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "postgresql://user:password@localhost/mydb"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(bind=engine)
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    username = Column(String, unique=True, index=True)
    email = Column(String, unique=True)
    hashed_password = Column(String)

# Dependency
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/users", response_model=list[UserResponse])
async def list_users(skip: int = 0, limit: int = 20, db: Session = Depends(get_db)):
    users = db.query(User).offset(skip).limit(limit).all()
    return users

Authentication with JWT

from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from jose import jwt, JWTError
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
security = HTTPBearer()

def create_token(data: dict, expires_delta: timedelta = timedelta(hours=24)):
    to_encode = data.copy()
    expire = datetime.utcnow() + expires_delta
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
    try:
        payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
        user_id = payload.get("sub")
        if user_id is None:
            raise HTTPException(status_code=401, detail="Invalid token")
        return user_id
    except JWTError:
        raise HTTPException(status_code=401, detail="Invalid token")

@app.get("/protected")
async def protected_route(user_id: str = Depends(get_current_user)):
    return {"message": f"Hello, user {user_id}"}

Error Handling

from fastapi import HTTPException
from fastapi.responses import JSONResponse

@app.exception_handler(ValueError)
async def value_error_handler(request, exc):
    return JSONResponse(
        status_code=400,
        content={"detail": str(exc)}
    )

@app.get("/users/{user_id}")
async def get_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

Testing

from fastapi.testclient import TestClient

client = TestClient(app)

def test_read_root():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Hello, World!"}

def test_create_user():
    response = client.post("/users", json={
        "username": "testuser",
        "email": "test@example.com",
        "password": "securepassword"
    })
    assert response.status_code == 201

Production Deployment

# Run with Gunicorn + Uvicorn workers
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

FastAPI makes building robust, well-documented APIs a pleasure. Its combination of performance, developer experience, and automatic validation makes it the top choice for new Python API projects in 2026.

Share this article:
Bas van den Berg
About the Author

Bas van den Berg

IT Administrator, Security Architect, Infrastructure Security Specialist, Technical Author

Bas van den Berg is an experienced IT Administrator and Security Architect specializing in the design, protection, and long-term operation of secure IT infrastructures.

With a strong background in system administration and cybersecurity, he has worked extensively with enterprise environments, focusing on access control...

IT Administration Security Architecture Network Security System Hardening Access Control

Stay Updated

Subscribe to our newsletter for the latest tutorials, tips, and exclusive offers.