FastAPI Tutorial: Build a REST API in Python

A
Author
04 Oct, 2026 1 min read 1.17K views

FastAPI is a Python web framework built on type hints. You describe your inputs and outputs with types, and FastAPI validates requests, serialises responses and generates interactive API docs for you.

Install and run

pip install "fastapi[standard]"
fastapi dev main.py      # auto-reload for development

A small CRUD API

# main.py
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel

app = FastAPI(title="Books API")

class BookIn(BaseModel):
    title: str
    author: str
    year: int | None = None

class Book(BookIn):
    id: int

books: dict[int, Book] = {}
next_id = 1

@app.get("/books")
def list_books(author: str | None = None, limit: int = 20) -> list[Book]:
    items = [b for b in books.values() if author is None or b.author == author]
    return items[:limit]

@app.get("/books/{book_id}")
def get_book(book_id: int) -> Book:
    if book_id not in books:
        raise HTTPException(status_code=404, detail="Book not found")
    return books[book_id]

@app.post("/books", status_code=status.HTTP_201_CREATED)
def create_book(data: BookIn) -> Book:
    global next_id
    book = Book(id=next_id, **data.model_dump())
    books[book.id] = book
    next_id += 1
    return book

@app.delete("/books/{book_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_book(book_id: int) -> None:
    books.pop(book_id, None)

What you get for free

  • book_id: int in the path is converted and validated: /books/abc returns a 422 with a clear error.
  • author and limit become optional query parameters.
  • The BookIn body is validated against the model.
  • The return type annotation filters and documents the response.
  • Interactive docs at /docs (Swagger UI) and /redoc.

Async or sync?

Use async def when the endpoint awaits async libraries (async database drivers, httpx). Use plain def for blocking code; FastAPI runs it in a thread pool so it doesn't block other requests.

For production, run fastapi run main.py (or Uvicorn directly) behind a reverse proxy.

Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.