🚀 FastAPI + PostgreSQL + Docker — Full CRUD Tutorial (Production Ready)
Welcome to the most complete hands-on FastAPI tutorial for students! This guide will show you how to build a real CRUD API using:
- FastAPI
- PostgreSQL (real database)
- SQLAlchemy ORM
- Alembic migrations
- Docker & Docker Compose
🐳 Why Docker? (Simple Explanation)
Docker allows you to package your entire FastAPI project and PostgreSQL database in one portable environment.
Benefits for Students:
- No need to separately install PostgreSQL.
- No database configuration headaches.
- The whole app runs using ONE command: docker-compose up --build
- Everyone in the class runs the same environment.
What Docker Compose Does
| Service | Description |
|---|---|
| db | Runs PostgreSQL database in a container |
| api | Runs FastAPI server inside its own container |
This is modern industry practice — and perfect for teaching!
📁 Project Structure
project/
│── app/
│ │── main.py
│ │── database.py
│ │── models.py
│ │── schemas.py
│ │── crud.py
│ │── __init__.py
│── Dockerfile
│── docker-compose.yml
│── requirements.txt
1️⃣ database.py — Database Connection
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
DATABASE_URL = "postgresql://postgres:postgres@db:5432/fastapi_db"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)
Base = declarative_base()
2️⃣ models.py — SQLAlchemy ORM Model
from sqlalchemy import Column, Integer, String, Float, Boolean
from .database import Base
class Item(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
price = Column(Float)
description = Column(String, nullable=True)
in_stock = Column(Boolean, default=True)
3️⃣ schemas.py — Pydantic Models
from pydantic import BaseModel
class ItemBase(BaseModel):
name: str
price: float
description: str | None = None
in_stock: bool = True
class ItemCreate(ItemBase):
pass
class Item(ItemBase):
id: int
class Config:
orm_mode = True
4️⃣ crud.py — All CRUD Operations
from sqlalchemy.orm import Session
from . import models, schemas
def create_item(db: Session, item: schemas.ItemCreate):
db_item = models.Item(**item.dict())
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
def get_items(db: Session):
return db.query(models.Item).all()
def get_item(db: Session, id: int):
return db.query(models.Item).filter(models.Item.id == id).first()
def update_item(db: Session, id: int, new_data: schemas.ItemCreate):
item = db.query(models.Item).filter(models.Item.id == id).first()
if item:
for k, v in new_data.dict().items():
setattr(item, k, v)
db.commit()
db.refresh(item)
return item
def delete_item(db: Session, id: int):
item = db.query(models.Item).filter(models.Item.id == id).first()
if item:
db.delete(item)
db.commit()
return item
5️⃣ main.py — FastAPI Routes
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from . import models, schemas, crud
from .database import engine, SessionLocal
# Create tables
models.Base.metadata.create_all(bind=engine)
app = FastAPI(title="FastAPI + Postgres CRUD")
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.post("/items/", response_model=schemas.Item)
def create(item: schemas.ItemCreate, db: Session = Depends(get_db)):
return crud.create_item(db, item)
@app.get("/items/", response_model=list[schemas.Item])
def read_all(db: Session = Depends(get_db)):
return crud.get_items(db)
@app.get("/items/{id}", response_model=schemas.Item)
def read_one(id: int, db: Session = Depends(get_db)):
item = crud.get_item(db, id)
if not item:
raise HTTPException(404, "Item not found")
return item
@app.put("/items/{id}", response_model=schemas.Item)
def update(id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)):
updated = crud.update_item(db, id, item)
if not updated:
raise HTTPException(404, "Item not found")
return updated
@app.delete("/items/{id}")
def delete(id: int, db: Session = Depends(get_db)):
deleted = crud.delete_item(db, id)
if not deleted:
raise HTTPException(404, "Item not found")
return {"message": "Deleted successfully"}
🐳 Dockerfile
FROM python:3.11
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY ./app ./app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
🐳 docker-compose.yml
version: "3.9"
services:
db:
image: postgres:15
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: fastapi_db
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
api:
build: .
ports:
- "8000:8000"
depends_on:
- db
volumes:
pgdata:
📦 requirements.txt
fastapi
uvicorn
sqlalchemy
psycopg2-binary
pydantic
▶ How to Run Everything
1️⃣ Build + Start all containers
docker-compose up --build
2️⃣ Open your browser
http://127.0.0.1:8000/docs
✔ Ready for CRUD ✔ Auto docs ✔ Real PostgreSQL ✔ Production ready
No comments:
Post a Comment