Advertisement
programming Learn how to build a real-world CRUD REST API in Python using FastAPI. Includes routing, validation, data models, error handling, and best practices.

How do I build a real CRUD API using FastAPI — with validation and clean structure?

5 Min Read Verified Content

FastAPI has exploded in popularity because:

✔ It’s fast (built on Starlette + Pydantic)
✔ Auto-docs with Swagger
✔ Type-safe
✔ Perfect for microservices & modern APIs

Let’s build a Users API with full CRUD.


📦 Step 1 — Install FastAPI & Uvicorn

pip install fastapi uvicorn

Run server later with:

uvicorn main:app --reload

🏗 Step 2 — Create main.py

from fastapi import FastAPI app = FastAPI() @app.get("/") def home(): return {"message": "FastAPI is running 🚀"}

Run it — open:

http://127.0.0.1:8000/docs

Yes — you already get Swagger UI for free.


🧩 Step 3 — Create a User Model (Validation Included)

FastAPI uses Pydantic models for validation.

from pydantic import BaseModel, EmailStr class User(BaseModel): id: int name: str email: EmailStr

We’ll use an in-memory list (like a fake DB first):

users = []

➕ Step 4 — Create User (POST)

@app.post("/users") def create_user(user: User): users.append(user) return user

Now when you send JSON:

{ "id": 1, "name": "John", "email": "john@email.com" }

FastAPI will:

✔ Validate email
✔ Validate types
✔ Auto-document everything


📖 Step 5 — Get All Users (GET)

@app.get("/users") def get_users(): return users

🔍 Step 6 — Get User by ID

from fastapi import HTTPException @app.get("/users/{user_id}") def get_user(user_id: int): for user in users: if user.id == user_id: return user raise HTTPException(status_code=404, detail="User not found")

Clean, readable, predictable.


✏️ Step 7 — Update User (PUT)

@app.put("/users/{user_id}") def update_user(user_id: int, updated: User): for i, user in enumerate(users): if user.id == user_id: users[i] = updated return updated raise HTTPException(status_code=404, detail="User not found")

❌ Step 8 — Delete User (DELETE)

@app.delete("/users/{user_id}") def delete_user(user_id: int): for i, user in enumerate(users): if user.id == user_id: users.pop(i) return {"message": "User deleted"} raise HTTPException(status_code=404, detail="User not found")

You now have a complete CRUD API.


🔥 Bonus — Partial Update (PATCH)

Sometimes you only want to update one field.

from typing import Optional class UserUpdate(BaseModel): name: Optional[str] email: Optional[EmailStr] @app.patch("/users/{user_id}") def patch_user(user_id: int, data: UserUpdate): for user in users: if user.id == user_id: if data.name: user.name = data.name if data.email: user.email = data.email return user raise HTTPException(status_code=404, detail="User not found")

🧠 Common Problems & Fixes

❌ Pydantic Validation Errors

Means your JSON doesn’t match the model.
Check keys & types.


❌ “Address already in use”

Stop previous server:

ctrl + c

Or change port:

uvicorn main:app --reload --port 9000

❌ CORS Error (Frontend Calling API)

Install:

pip install fastapi[all]

Add:

from fastapi.middleware.cors import CORSMiddleware app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], )

🏗 Real-World Folder Structure (When App Grows)

app/ ┣ models.py ┣ routes.py ┣ db.pymain.py

Keeps things clean.


📌 Best Practices

✔ Use environment variables
✔ Validate all inputs
✔ Use async where possible
✔ Prefer schemas over raw dicts
✔ Add logging


🏁 Final Thoughts

FastAPI makes API development feel modern again:

👉 type-safe
👉 fast
👉 minimal boilerplate
👉 built-in docs

Once you grasp:

model → route → validation → response

…you can build production-grade APIs quickly and safely.

Advertisement
Back to Programming