If you have ever wanted to build a backend without drowning in boilerplate, this FastAPI REST API tutorial is for you. FastAPI is one of the fastest growing Python frameworks in 2026, and for good reason: it is async-ready, type-safe, and ridiculously beginner friendly. By the end of this guide, you will have a working REST API with validated input and a real database connection, all in under an hour.
Unlike longer documentation walkthroughs, this tutorial focuses on shipping something that works today. No abstract theory, no 12-chapter detour. Just the practical steps.
Why FastAPI for Your First REST API?
Before we dive into the code, here is why FastAPI has become a top choice for developers building REST APIs in Python:
- Automatic interactive docs via Swagger UI and ReDoc
- Built-in data validation through Pydantic v2
- Native async support for high concurrency
- Type hints double as your API contract
- Used in production by companies like Netflix, Uber, and Microsoft

What You Will Build
A small Books API with these endpoints:
| Method | Route | Purpose |
|---|---|---|
| GET | /books | List all books |
| GET | /books/{id} | Get a single book |
| POST | /books | Create a new book |
| PUT | /books/{id} | Update a book |
| DELETE | /books/{id} | Delete a book |
Step 1: Set Up Your Environment
Make sure you have Python 3.10 or higher installed. Create a project folder and a virtual environment:
mkdir books-api && cd books-api
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install fastapi uvicorn[standard] sqlalchemy pydantic
Project structure
- main.py for the FastAPI app and routes
- models.py for SQLAlchemy database models
- schemas.py for Pydantic schemas
- database.py for the DB connection
Step 2: Create the Database Connection
We will use SQLite to keep things simple. Create database.py:
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base, sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./books.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

Step 3: Define Your Database Model
In models.py:
from sqlalchemy import Column, Integer, String
from database import Base
class Book(Base):
__tablename__ = "books"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
author = Column(String, index=True)
year = Column(Integer)
Step 4: Add Pydantic Schemas for Validation
This is where FastAPI really shines. Pydantic validates incoming requests automatically. Create schemas.py:
from pydantic import BaseModel, Field
class BookBase(BaseModel):
title: str = Field(..., min_length=1, max_length=200)
author: str = Field(..., min_length=1, max_length=100)
year: int = Field(..., ge=1450, le=2026)
class BookCreate(BookBase):
pass
class BookOut(BookBase):
id: int
class Config:
from_attributes = True
Notice how we set rules: year must be between 1450 and 2026, title cannot be empty. If a client sends invalid data, FastAPI returns a clean 422 error automatically.
Step 5: Build the Routes in main.py
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List
import models, schemas
from database import engine, get_db
models.Base.metadata.create_all(bind=engine)
app = FastAPI(title="Books API", version="1.0.0")
@app.get("/books", response_model=List[schemas.BookOut])
def list_books(db: Session = Depends(get_db)):
return db.query(models.Book).all()
@app.get("/books/{book_id}", response_model=schemas.BookOut)
def get_book(book_id: int, db: Session = Depends(get_db)):
book = db.query(models.Book).filter(models.Book.id == book_id).first()
if not book:
raise HTTPException(status_code=404, detail="Book not found")
return book
@app.post("/books", response_model=schemas.BookOut, status_code=201)
def create_book(book: schemas.BookCreate, db: Session = Depends(get_db)):
new_book = models.Book(**book.model_dump())
db.add(new_book)
db.commit()
db.refresh(new_book)
return new_book
@app.put("/books/{book_id}", response_model=schemas.BookOut)
def update_book(book_id: int, book: schemas.BookCreate, db: Session = Depends(get_db)):
db_book = db.query(models.Book).filter(models.Book.id == book_id).first()
if not db_book:
raise HTTPException(status_code=404, detail="Book not found")
for key, value in book.model_dump().items():
setattr(db_book, key, value)
db.commit()
db.refresh(db_book)
return db_book
@app.delete("/books/{book_id}", status_code=204)
def delete_book(book_id: int, db: Session = Depends(get_db)):
db_book = db.query(models.Book).filter(models.Book.id == book_id).first()
if not db_book:
raise HTTPException(status_code=404, detail="Book not found")
db.delete(db_book)
db.commit()
return None
Step 6: Run Your API
Start the server with Uvicorn:
uvicorn main:app --reload
Then open the following URLs in your browser:
- http://127.0.0.1:8000/docs for the Swagger UI
- http://127.0.0.1:8000/redoc for the ReDoc interface
You can now create, list, update, and delete books straight from the interactive docs. No Postman required.

Step 7: Test It With curl
curl -X POST http://127.0.0.1:8000/books \
-H "Content-Type: application/json" \
-d '{"title":"Clean Code","author":"Robert C. Martin","year":2008}'
You should get a 201 response with the new book and its assigned ID.
Common Pitfalls to Avoid
- Forgetting to call
db.commit()after changes - Using mutable default arguments in Pydantic models
- Not closing DB sessions (use the
Depends(get_db)pattern shown above) - Returning SQLAlchemy objects without a response_model in production
Next Steps to Level Up
Once your first API is running, here is what to tackle next:
- Add JWT authentication with python-jose
- Switch SQLite for PostgreSQL in production
- Add Alembic migrations for schema versioning
- Write tests using pytest and the FastAPI TestClient
- Deploy with Docker and a process manager like Gunicorn + Uvicorn workers
FAQ
Can we build a REST API using FastAPI?
Yes. FastAPI is purpose-built for REST APIs. It handles routing, validation, serialization, and OpenAPI documentation out of the box.
Is FastAPI a REST API framework?
FastAPI is a web framework that excels at building REST APIs, but it can also serve GraphQL, WebSockets, and async background tasks.
Is FastAPI beginner friendly?
Absolutely. Thanks to Python type hints, automatic docs, and clear error messages, most beginners can ship a working API in less than an hour, as this tutorial demonstrates.
Is FastAPI used in production by big companies?
Yes. Netflix, Uber, Microsoft, and many fintech startups use FastAPI in production for internal tools and customer-facing APIs.
Do I need to know async Python to use FastAPI?
No. You can write standard synchronous route functions (as we did in this tutorial). Async is a bonus when you need higher throughput.
Wrapping Up
You now have a complete FastAPI REST API with database persistence, input validation, and interactive documentation. The same patterns scale up to large production systems. Bookmark this tutorial, fork the code, and start building.
Happy shipping from the team at adproductstogo.com.

