Let’s get a FastAPI app actually running. Three steps: install, write a file, run uvicorn.
Install
pip install "fastapi[standard]"
The [standard] extra pulls in uvicorn and a few useful goodies (httpx for the test client, email-validator, etc.). If we want bare-bones we can do pip install fastapi uvicorn instead.
The smallest app
Create main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello from FastAPI"}
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id, "name": f"Item #{item_id}"}
A few things to notice:
app = FastAPI()creates the application instance. Everything attaches to this.@app.get("/")registers a GET handler at/. Same pattern as Flask but on the app instance.- The function can be
async defor plaindef. FastAPI handles both — plaindefruns in a threadpool so we don’t block the event loop. - The dict we return gets serialized to JSON automatically.
Run it
uvicorn main:app --reload
Breaking down main:app — main is the Python module (the file main.py), app is the variable name inside that file. --reload watches files and restarts on change. Only use it in dev.
Output should look like:
INFO: Uvicorn running on http://127.0.0.1:8000
INFO: Started reloader process
INFO: Application startup complete.
Hit http://localhost:8000/ in a browser and we get {"message": "Hello from FastAPI"}.
The free docs
This is the magic. Without writing any extra code, go to:
http://localhost:8000/docs— interactive Swagger UI. We can expand each endpoint and hit “Try it out” to fire real requests.http://localhost:8000/redoc— ReDoc-style docs (cleaner, three-column layout, better for reading).http://localhost:8000/openapi.json— the raw OpenAPI 3.1 spec as JSON. Useful for client codegen.
Test it from the terminal
curl http://localhost:8000/items/42
# {"item_id":42,"name":"Item #42"}
curl http://localhost:8000/items/abc
# {"detail":[{"type":"int_parsing","loc":["path","item_id"],...}]}
That second response is FastAPI rejecting abc because we typed item_id as int. We got validation for free.
App-level options
FastAPI() accepts a bunch of kwargs that show up in the docs:
app = FastAPI(
title="Inventory Service",
description="Manages items, stock levels, and reorders.",
version="0.1.0",
docs_url="/swagger", # change default /docs path
redoc_url=None, # disable redoc
)
In prod we usually set docs_url=None and redoc_url=None to hide internal docs from the public.
fastapi dev (newer way)
Recent FastAPI versions ship a CLI:
fastapi dev main.py
Same thing as uvicorn main:app --reload but with nicer output. For prod use fastapi run main.py which skips the reloader.
That’s it — we have a working API, free docs, and validation. The rest is just adding more routes.