DEV Community

DevCorner2
DevCorner2

Posted on

πŸš€ Building a CRUD Application with FastAPI – A Complete Guide

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. It’s designed to be easy to use while delivering the best developer experience.

In this blog, we'll walk through building a full CRUD (Create, Read, Update, Delete) application using FastAPI with a SQLite database via SQLAlchemy.


🧠 What You'll Learn

  • Setting up a FastAPI project
  • Connecting FastAPI to a SQLite database using SQLAlchemy
  • Creating database models
  • Writing API routes for CRUD operations
  • Using Pydantic models for validation
  • Testing the API using Swagger UI

πŸ“ Project Structure

fastapi-crud/
β”‚
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ main.py
β”‚   β”œβ”€β”€ database.py
β”‚   β”œβ”€β”€ models.py
β”‚   β”œβ”€β”€ schemas.py
β”‚   └── crud.py
β”‚
β”œβ”€β”€ requirements.txt
└── README.md
Enter fullscreen mode Exit fullscreen mode

βš™οΈ Step 1: Setup and Installation

Create a folder and install FastAPI and dependencies:

mkdir fastapi-crud
cd fastapi-crud
python -m venv env
source env/bin/activate
pip install fastapi uvicorn sqlalchemy pydantic
Enter fullscreen mode Exit fullscreen mode

Create a requirements.txt:

fastapi
uvicorn
sqlalchemy
pydantic
Enter fullscreen mode Exit fullscreen mode

πŸ› οΈ Step 2: Database Configuration – database.py

# app/database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"

engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()
Enter fullscreen mode Exit fullscreen mode

🧱 Step 3: Models – models.py

# app/models.py
from sqlalchemy import Column, Integer, String
from .database import Base

class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String, index=True)
    description = Column(String, index=True)
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ Step 4: Schemas – schemas.py

# app/schemas.py
from pydantic import BaseModel

class ItemBase(BaseModel):
    title: str
    description: str

class ItemCreate(ItemBase):
    pass

class Item(ItemBase):
    id: int

    class Config:
        orm_mode = True
Enter fullscreen mode Exit fullscreen mode

βš™οΈ Step 5: CRUD Logic – crud.py

# app/crud.py
from sqlalchemy.orm import Session
from . import models, schemas

def get_item(db: Session, item_id: int):
    return db.query(models.Item).filter(models.Item.id == item_id).first()

def get_items(db: Session, skip: int = 0, limit: int = 10):
    return db.query(models.Item).offset(skip).limit(limit).all()

def create_item(db: Session, item: schemas.ItemCreate):
    db_item = models.Item(title=item.title, description=item.description)
    db.add(db_item)
    db.commit()
    db.refresh(db_item)
    return db_item

def delete_item(db: Session, item_id: int):
    item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if item:
        db.delete(item)
        db.commit()
    return item

def update_item(db: Session, item_id: int, item_data: schemas.ItemCreate):
    item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if item:
        item.title = item_data.title
        item.description = item_data.description
        db.commit()
        db.refresh(item)
    return item
Enter fullscreen mode Exit fullscreen mode

πŸš€ Step 6: FastAPI Main App – main.py

# app/main.py
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from . import models, schemas, crud
from .database import SessionLocal, engine, Base

Base.metadata.create_all(bind=engine)

app = FastAPI()

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

@app.post("/items/", response_model=schemas.Item)
def create_item(item: schemas.ItemCreate, db: Session = Depends(get_db)):
    return crud.create_item(db=db, item=item)

@app.get("/items/", response_model=list[schemas.Item])
def read_items(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    return crud.get_items(db, skip=skip, limit=limit)

@app.get("/items/{item_id}", response_model=schemas.Item)
def read_item(item_id: int, db: Session = Depends(get_db)):
    db_item = crud.get_item(db, item_id=item_id)
    if db_item is None:
        raise HTTPException(status_code=404, detail="Item not found")
    return db_item

@app.put("/items/{item_id}", response_model=schemas.Item)
def update_item(item_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)):
    updated = crud.update_item(db, item_id, item)
    if updated is None:
        raise HTTPException(status_code=404, detail="Item not found")
    return updated

@app.delete("/items/{item_id}", response_model=schemas.Item)
def delete_item(item_id: int, db: Session = Depends(get_db)):
    deleted = crud.delete_item(db, item_id)
    if deleted is None:
        raise HTTPException(status_code=404, detail="Item not found")
    return deleted
Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ Step 7: Run and Test

Run the app:

uvicorn app.main:app --reload
Enter fullscreen mode Exit fullscreen mode

Navigate to:

πŸ“š Swagger UI: http://127.0.0.1:8000/docs

🧾 Redoc UI: http://127.0.0.1:8000/redoc


🧼 Optional Enhancements

  • Add authentication (JWT)
  • Migrate to PostgreSQL/MySQL
  • Integrate Alembic for migrations
  • Use FastAPI Users for user management

πŸ“ Conclusion

FastAPI makes it incredibly easy to build powerful APIs with Python. This CRUD app demonstrated how to set up models, schemas, database interaction, and API routes.

Want to go further? Add frontend integration with React or Vue, deploy with Docker, or move to production with Gunicorn + Uvicorn!

Top comments (0)