Python for JS Devs · FastAPI

Your first FastAPI app

If you've built an Express server, you'll have a FastAPI one running in five minutes — with free interactive docs on top.

Lesson 11Time ~12 min Win A running API with live /docsPrereq Lessons 06, 10

1 · Install & the smallest app

uv init api-demo && cd api-demo
uv python pin 3.13
uv add fastapi "uvicorn[standard]"

Create main.py:

Express
const app = express();

app.get("/", (req, res) => {
  res.json({ ok: true });
});

app.listen(8000);
FastAPI
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def root():
    return {"ok": True}   # dict → JSON automatically

Two things jump out: routes are decorators (@app.get("/")) on a function, and you return a value instead of calling res.json() — FastAPI serializes whatever you return.

2 · Run it (uvicorn is your listen)

uv run uvicorn main:app --reload
# main:app  →  the `app` object inside main.py
# --reload  →  hot reload, like nodemon

Open http://127.0.0.1:8000. Then the payoff Express doesn't give you for free:

Free interactive docs Visit /docs for a live Swagger UI where you can call your endpoints, and /openapi.json for the generated OpenAPI schema. FastAPI builds these from your routes and type hints automatically — no annotations library, no decorators to maintain. This alone is a reason teams pick it.

3 · Path & query params from the signature

Here's the FastAPI "aha": function parameters are the request contract, read from your type hints (Lesson 06 pays off now).

@app.get("/items/{item_id}")
def get_item(item_id: int, q: str | None = None):
    # item_id comes from the PATH and is validated as int
    # q comes from the QUERY string (?q=...) and is optional
    return {"item_id": item_id, "q": q}

Because item_id: int, hitting /items/abc auto-returns a clean 422 validation error — you wrote zero validation code. A parameter named in the path ({item_id}) is a path param; any other parameter with a scalar type becomes a query param.

🎯 Your win

Get the app running with --reload, add the /items/{item_id} route, then open /docs and call it from the browser. Try /items/abc and watch FastAPI reject it with a 422. A running, self-documenting API is the win — everything else builds on this.

Check yourself

Q1. How does a FastAPI handler send a JSON response?
Return a value; FastAPI serializes it to JSON automatically.
Q2. Where does FastAPI's interactive docs live?
/docs (Swagger UI) and /openapi.json are generated automatically from your routes and hints.
Q3. A handler param item_id: int not in the path is treated as:
Scalar params not named in the path become validated query parameters.
Primary source FastAPI — First Steps. The official tutorial; do its first few pages alongside this. See the FastAPI cheat sheet.
💬 Ask your teacher: def vs async def for a route — which should I use here? (Big one — it's the whole of Lesson 17. Ask now if curious.)