Skillversitas

CRUD Operations

CRUD - Create, Read, Update, Delete - is the backbone of most APIs. This chapter assembles the pieces you already know (models, path/query parameters, response models, status codes) into a complete resource API with consistent conventions.

Models First

from pydantic import BaseModel, Field

class ItemCreate(BaseModel):
    name: str
    price: float = Field(gt=0)
    tags: list[str] = []

class ItemOut(ItemCreate):
    id: int

class ItemUpdate(BaseModel):
    name: str | None = None
    price: float | None = Field(default=None, gt=0)

An In-Memory Store

from fastapi import FastAPI, HTTPException, status

app = FastAPI()
items_db: dict[int, ItemOut] = {}
next_id = 1

@app.post("/items/", response_model=ItemOut, status_code=status.HTTP_201_CREATED)
def create_item(item: ItemCreate):
    global next_id
    out = ItemOut(id=next_id, **item.model_dump())
    items_db[next_id] = out
    next_id += 1
    return out

@app.get("/items/", response_model=list[ItemOut])
def list_items(skip: int = 0, limit: int = 100):
    return list(items_db.values())[skip:skip + limit]

@app.get("/items/{item_id}", response_model=ItemOut)
def read_item(item_id: int):
    item = items_db.get(item_id)
    if item is None:
        raise HTTPException(status_code=404, detail="Item not found")
    return item

@app.patch("/items/{item_id}", response_model=ItemOut)
def update_item(item_id: int, item: ItemUpdate):
    current = items_db.get(item_id)
    if current is None:
        raise HTTPException(status_code=404, detail="Item not found")
    data = current.model_dump()
    data.update({k: v for k, v in item.model_dump().items() if v is not None})
    updated = ItemOut(**data)
    items_db[item_id] = updated
    return updated

@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_item(item_id: int):
    if item_id not in items_db:
        raise HTTPException(status_code=404, detail="Item not found")
    del items_db[item_id]
    return None

Conventions in the Code

  • POST returns 201 with the created resource; DELETE returns 204 with no body.
  • PATCH is a partial update: None fields mean "unchanged".
  • Missing resources are 404, not 500 - raise HTTPException explicitly.
  • List endpoints accept skip/limit for pagination from day one.
  • Separate Create/Update/Out models keep input and output contracts independent.

Summary

A CRUD API is a set of conventions applied to the tools you already have: Pydantic models for in/out, path and query parameters, 201/204/404 status codes, and a store (in-memory here, a database later). Follow the same shape for every resource and the API stays predictable as it grows.