FastAPI/
Lesson

Standing up a working APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. in FastAPI takes about ten lines of code. That is not an exaggeration, the framework is designed to get you from zero to a testable API in under a minute. In this lesson you will build that first app, understand the structure AI generates, and explore the documentation endpoints that make FastAPI uniquely developer-friendly.

The minimal FastAPI app

Create a file called main.py:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

Run it with:

uvicorn main:app --reload

Open your browser to http://localhost:8000 and you will see {"message": "Hello World"}. That is your APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses., running and serving JSONWhat is json?A text format for exchanging data between systems. It uses key-value pairs and arrays, and every programming language can read and write it..

Let us break down the uvicorn command:

PartMeaning
uvicornThe ASGI server that runs your app
mainThe Python file (main.py, without the extension)
appThe variable name of your FastAPI instance
--reloadAuto-restart when you save changes (dev only)
Uvicorn is to FastAPI what node index.js is to Express. It is the server process that listens for HTTP connections and passes requests to your FastAPI application. In production, you would use gunicorn with uvicorn workers or deploy behind a reverse proxy, but for development uvicorn --reload is all you need.
02

Route decorators: the path operations

FastAPI uses Python decorators to connect URL paths to handler functions. Each decorator corresponds to an HTTPWhat is http?The protocol browsers and servers use to exchange web pages, API data, and other resources, defining how requests and responses are formatted. method.

from fastapi import FastAPI

app = FastAPI()

@app.get("/items")
async def list_items():
    return [{"id": 1, "name": "Widget"}, {"id": 2, "name": "Gadget"}]

@app.post("/items")
async def create_item():
    return {"id": 3, "name": "New item"}

@app.put("/items/{item_id}")
async def update_item(item_id: int):
    return {"id": item_id, "updated": True}

@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
    return {"deleted": item_id}

FastAPI calls these "path operations", each one is the combination of an HTTP method and a URL path. The handler function (called a "path operation function") is the Python function that runs when that method+path combination is requested.

DecoratorHTTP methodTypical use
@app.getGETRead data
@app.postPOSTCreate a resource
@app.putPUTReplace a resource entirely
@app.patchPATCHPartially update a resource
@app.deleteDELETERemove a resource
03

Return values and automatic JSONWhat is json?A text format for exchanging data between systems. It uses key-value pairs and arrays, and every programming language can read and write it. serializationWhat is serialization?Converting data from a program's internal format into a string or byte sequence that can be stored or sent over a network.

Notice that the handler functions return plain Python dictionaries and lists. FastAPI automatically converts them to JSON responses with the correct Content-Type: application/json header. You never need to call a jsonify() function like in Flask.

@app.get("/status")
async def status():
    # Return a dict - FastAPI converts to JSON automatically
    return {"status": "ok", "version": "1.0.0"}

This also works with Pydantic models, dataclasses, and any object that can be serialized to JSON. FastAPI handles the conversion transparently.

04

The app structure AI generates

When you ask AI to "create a FastAPI CRUDWhat is crud?Create, Read, Update, Delete - the four basic operations almost every application performs on data. app for managing books," the generated code almost always follows this structure:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

# --- Pydantic models ---
class Book(BaseModel):
    title: str
    author: str
    year: int

# --- In-memory storage ---
books: list[Book] = []

# --- Endpoints ---
@app.get("/books")
async def get_books():
    return books

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

@app.post("/books", status_code=201)
async def create_book(book: Book):
    books.append(book)
    return book

@app.delete("/books/{book_id}")
async def delete_book(book_id: int):
    if book_id >= len(books):
        raise HTTPException(status_code=404, detail="Book not found")
    return books.pop(book_id)

This is a recognizable pattern: imports at the top, Pydantic models for data shapes, an in-memory data store, and CRUD endpoints. AI generates this structure reliably because it appears thousands of times in FastAPI tutorials and documentation.

AI pitfall
AI-generated CRUD apps almost always use an in-memory list or dictionary as the data store. This works for demos but data disappears when the server restarts. If AI presents this as "production-ready," it is not, you need a real database. Also watch for list-index-based IDs (like the example above), in production, use UUIDs or database-generated IDs.
05

The /docs and /redoc endpoints

This is the feature that sets FastAPI apart from every other Python framework. The moment your app starts, two documentation endpoints are live.

Swagger UI at /docs

Navigate to http://localhost:8000/docs and you get a fully interactive APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. explorer. Every endpointWhat is endpoint?A specific URL path on a server that handles a particular type of request, like GET /api/users. is listed with its HTTPWhat is http?The protocol browsers and servers use to exchange web pages, API data, and other resources, defining how requests and responses are formatted. method, path, parameters, and request/response schemas. You can expand any endpoint, fill in parameters, click "Try it out," and send real requests, all from the browser.

This is generated entirely from your code. The type annotations on your function parameters, the Pydantic models, and the status codes you set all feed into the OpenAPIWhat is openapi?A standard format for describing REST APIs - their endpoints, parameters, and response shapes. Tools can generate documentation and client libraries from it automatically. schemaWhat is schema?A formal definition of the structure your data must follow - which fields exist, what types they have, and which are required. that drives this interface.

ReDoc at /redoc

Navigate to http://localhost:8000/redoc for a read-only documentation view. ReDoc is better for sharing with API consumers who need to understand your endpoints but do not need to test them interactively. The layout is cleaner and more suited to browsing.

Why this matters for AI-generated code

When AI generates a FastAPI app, you can immediately verify what it built by visiting /docs. No need to write curl commands, open Postman, or build a frontend. The docs page shows you every endpoint, every expected parameter, and every response shape. If something looks wrong, a missing field, a wrong type, an incorrect status codeWhat is status code?A three-digit number in an HTTP response that tells the client what happened: 200 means success, 404 means not found, 500 means the server broke., you can catch it in seconds.

# AI generated this endpoint
@app.post("/users")
async def create_user(user: UserCreate):
    return {"id": 1, **user.model_dump()}

Visit /docs, expand the POST /users endpoint, and you will see the exact JSONWhat is json?A text format for exchanging data between systems. It uses key-value pairs and arrays, and every programming language can read and write it. schema the endpoint expects. If UserCreate has fields name: str and email: str, the docs page shows that. If AI forgot a field or used the wrong type, it is immediately visible.

06

Adding metadata to your app

FastAPI accepts metadata arguments that enrich the generated documentation:

app = FastAPI(
    title="Bookstore API",
    description="A simple API for managing books",
    version="1.0.0",
)

These values appear at the top of the /docs and /redoc pages. AI almost always includes title and sometimes description. Adding version is good practice for tracking which version of the APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. is deployed.

07

Running in production vs development

In development, you run:

uvicorn main:app --reload

In production, you drop --reload (it has performance overhead and watches the filesystem) and often use Gunicorn with Uvicorn workers for multi-process handling:

gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker

This runs four worker processes, each with its own event loopWhat is event loop?The mechanism that lets Node.js handle many operations on a single thread by delegating slow tasks and processing their results when ready.. For containerized deployments (DockerWhat is docker?A tool that packages your application and all its dependencies into a portable container that runs identically on any machine., Kubernetes), a single Uvicorn process per containerWhat is container?A lightweight, portable package that bundles your application code with all its dependencies so it runs identically on any machine. is common, with the orchestrator handling scaling.

AI pitfall
AI occasionally puts uvicorn.run(app, host="0.0.0.0", port=8000) at the bottom of main.py. This works for quick scripts but is not recommended for production because it bypasses Gunicorn's process management. For development, the CLI command uvicorn main:app --reload gives you hot-reloading. For production, use Gunicorn. The uvicorn.run() call inside your code is a convenience, not a best practice.