FASTAPI — 12‑Hour Hands‑On Tutorial
A 12‑hour, 12‑module hands‑on tutorial for learning FastAPI. Each module is designed to be completed in ~1 hour with clear objectives, step‑by‑step instructions, runnable code, tasks, and mini‑quizzes. Uses Prism.js for syntax highlighting in the code editor and includes a reusable Copy & Use button for each code block.
How to use this tutorial
Open the module you want to work on.
Follow the prerequisites and setup steps. Run commands in your terminal (VS Code recommended). The Visual Studio Code FastAPI tutorial and the Ultimate FastAPI Tutorial repository were used as references when designing these modules.
What you'll need
-
Python 3.10+ (recommended 3.11)
-
VS Code (optional but recommended) with Python extension
-
Git
-
Basic knowledge of Python and HTTP/JSON
-
A terminal (macOS/Linux) or PowerShell on Windows
Quick repo + starter template (optional)
Create a project folder to keep each module's work isolated:
mkdir fastapi-12hr && cd fastapi-12hr
python -m venv .venv
source .venv/bin/activate # macOS / Linux
.venv\Scripts\Activate # Windows PowerShell
pip install fastapi uvicorn[standard] pydantic
Prism.js + Copy & Use code editor (single reusable snippet)
Use this minimal HTML file (save as editor-template.html) to embed highlighted code with Prism.js, a live copy button, and a "Use" button that downloads the code as a file. This snippet appears before each module's code blocks so you can reuse it in your blog or learning platform.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Code editor with Prism</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css" rel="stylesheet" />
<style>
.code-wrap{position:relative;margin:1rem 0}
.code-actions{position:absolute;right:0;top:0}
.code-actions button{margin-left:.4rem}
pre{padding:1rem;overflow:auto;border-radius:.5rem}
</style>
</head>
<body>
<div class="code-wrap">
<div class="code-actions">
<button class="copy">Copy</button>
<button class="use">Use</button>
</div>
<pre><code id="code" class="language-python"># sample code will be replaced dynamically</code></pre>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script>
<script>
const codeEl = document.getElementById('code');
document.querySelector('.copy').addEventListener('click', async ()=>{
try{ await navigator.clipboard.writeText(codeEl.textContent); alert('Copied!'); }
catch(e){ alert('Copy failed: '+e.message); }
});
document.querySelector('.use').addEventListener('click', ()=>{
const blob = new Blob([codeEl.textContent], {type:'text/plain'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url; a.download = 'snippet.py'; a.click();
URL.revokeObjectURL(url);
});
// To load code dynamically, set codeEl.textContent = '...'; Prism.highlightElement(codeEl);
</script>
</body>
</html>
Note: Replace the
codeelement content dynamically when rendering module code blocks (server-side or client-side).
Module Index (12 modules — 1 hour each)
-
Module 1 — FastAPI basics & project setup
-
Module 2 — Path parameters, query params, request body
-
Module 3 — Data validation with Pydantic
-
Module 4 — Dependency injection & security basics
-
Module 5 — Background tasks, events, and middleware
-
Module 6 — Database integration (SQLite + SQLModel / SQLAlchemy)
-
Module 7 — Authentication (OAuth2 Password + JWT)
-
Module 8 — File uploads, streaming responses, and static files
-
Module 9 — Testing FastAPI (pytest + TestClient)
-
Module 10 — Async IO, performance tuning, and deployment basics (uvicorn/gunicorn)
-
Module 11 — Building a small real-world API (todo app) — put it all together
-
Module 12 — Documentation, OpenAPI customization, and next steps
Module 1 — FastAPI basics & project setup (60 minutes)
Goal
Create your first FastAPI app, run it with Uvicorn, and interact with the auto-generated docs.
Steps
-
Create
module1folder andmain.py.
# module1/main.py
from fastapi import FastAPI
app = FastAPI()
@app.get('/')
def read_root():
return {"message": "Hello, FastAPI!"}
-
Install dependencies and run server:
pip install fastapi uvicorn
uvicorn module1.main:app --reload
-
Open
http://127.0.0.1:8000/docs(Swagger UI) andhttp://127.0.0.1:8000/redoc(ReDoc).
Tasks
-
Change the path to
/hello/{name}and return a personalized message.
Mini quiz
-
Where does FastAPI take endpoint type hints from? (Answer: function annotations / type hints)
Module 2 — Path params, query params, request body (60 minutes)
Goal
Learn path parameters, query parameters, and how to accept JSON bodies.
Code
# module2/main.py
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
tags: list[str] = []
@app.get('/items/{item_id}')
def read_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "q": q}
@app.post('/items/')
def create_item(item: Item):
return {"created": item}
### Steps
- Run with uvicorn and test POST via `curl` or Swagger UI.
### Hands‑on exercises
- Add optional fields and default values; validate in requests.
---
## Module 3 — Data validation with Pydantic (60 minutes)
### Goal
Use Pydantic models for validation, nested models, and custom validators.
### Code
```python
# module3/main.py
from pydantic import BaseModel, validator
from typing import List
class User(BaseModel):
username: str
age: int
@validator('age')
def age_must_be_positive(cls, v):
if v < 0:
raise ValueError('age must be positive')
return v
class Group(BaseModel):
name: str
members: List[User]
### Exercises
- Add email validation, pre/post processing, and example schemas for docs.
---
## Module 4 — Dependency injection & security basics (60 minutes)
### Goal
Learn FastAPI dependencies and a simple API key header dependency.
### Code
```python
# module4/main.py
from fastapi import FastAPI, Depends, HTTPException, Header
app = FastAPI()
async def get_api_key(x_api_key: str | None = Header(None)):
if x_api_key != 'secret123':
raise HTTPException(status_code=401, detail='Unauthorized')
return x_api_key
@app.get('/secure')
async def secure_endpoint(api_key: str = Depends(get_api_key)):
return {"message": "Secure data"}
### Tasks
- Create a reusable dependency that reads a DB session (placeholder) and is injected into endpoints.
---
## Module 5 — Background tasks, events, and middleware (60 minutes)
### Goal
Use `BackgroundTasks` for async post-response work, and add startup/shutdown handlers + simple middleware.
### Code
```python
# module5/main.py
from fastapi import FastAPI, BackgroundTasks
app = FastAPI()
@app.on_event('startup')
def startup_event():
print('Starting up...')
def write_log(message: str):
with open('log.txt','a') as f:
f.write(message+'\n')
@app.post('/notify')
def notify(background_tasks: BackgroundTasks, msg: str):
background_tasks.add_task(write_log, msg)
return {'status': 'scheduled'}
### Exercises
- Add middleware that logs request paths and duration.
---
## Module 6 — Database integration (SQLite + SQLModel) (60 minutes)
### Goal
Connect FastAPI to a relational DB using SQLModel (a modern wrapper on SQLAlchemy) and perform CRUD.
### Install
pip install sqlmodel[sqlite] sqlalchemy aiosqlite
### Code
```python
# module6/models.py
from sqlmodel import SQLModel, Field, create_engine, Session, select
class Todo(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
title: str
done: bool = False
sqlite_url = 'sqlite:///./todos.db'
engine = create_engine(sqlite_url, echo=True)
def init_db():
SQLModel.metadata.create_all(engine)
# module6/main.py
from fastapi import FastAPI
from .models import Todo, engine, init_db
from sqlmodel import Session, select
app = FastAPI()
init_db()
@app.post('/todos/')
def create_todo(todo: Todo):
with Session(engine) as session:
session.add(todo); session.commit(); session.refresh(todo)
return todo
@app.get('/todos/')
def list_todos():
with Session(engine) as session:
return session.exec(select(Todo)).all()
Tasks
-
Add update and delete endpoints. Add async DB connections if desired.
Module 7 — Authentication (OAuth2 Password + JWT) (60 minutes)
Goal
Implement OAuth2 password flow and JWT-based token generation.
Install
pip install python-jose[bcrypt] passlib[bcrypt]
Code (sketch)
# module7/auth.py (sketch)
from datetime import datetime, timedelta
from jose import jwt
from passlib.context import CryptContext
SECRET_KEY = 'CHANGE_ME'
ALGORITHM = 'HS256'
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto')
# functions: verify_password, get_password_hash, create_access_token
Steps
-
Create endpoints for
/tokenthat return JWT token after verifying username/password. -
Protect endpoints with
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='token')and aget_current_userdependency.
Module 8 — File uploads, streaming responses, and static files (60 minutes)
Goal
Learn how to accept file uploads, stream large files, and serve static content.
Code
# module8/main.py
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import StreamingResponse
app = FastAPI()
@app.post('/upload')
async def upload(file: UploadFile = File(...)):
contents = await file.read()
return {'filename': file.filename, 'size': len(contents)}
@app.get('/download')
def download():
def iterfile():
with open('largefile.bin','rb') as f:
yield from f
return StreamingResponse(iterfile())
Tasks
-
Add static files mount:
app.mount('/static', StaticFiles(directory='static'), name='static')
Module 9 — Testing FastAPI (pytest + TestClient) (60 minutes)
Goal
Write unit tests and integration tests for endpoints using pytest and fastapi.testclient.
Install
pip install pytest httpx
Example test
# module9/test_main.py
from fastapi.testclient import TestClient
from module1.main import app
client = TestClient(app)
def test_read_root():
resp = client.get('/')
assert resp.status_code == 200
assert resp.json() == {'message': 'Hello, FastAPI!'}
Tasks
-
Add fixture to create test DB and teardown after tests.
Module 10 — Async IO, performance tuning, and deployment basics (60 minutes)
Goal
Make endpoints asynchronous, learn best practices, and deploy with Uvicorn / Gunicorn.
Tips
-
Use
async deffor I/O-bound endpoints. -
Avoid blocking calls; run blocking code with
run_in_executor.
Command (uvicorn)
uvicorn module11.main:app --host 0.0.0.0 --port 8000 --workers 4
Deploy notes
-
For Docker, create a
Dockerfileusing an ASGI server. For production, prefer multiple workers behind a load balancer.
Module 11 — Build a small real-world API (Todo app) (60 minutes)
Goal
Combine modules: Pydantic validation, DB, auth, tests, and docs into a small Todo API.
Structure (suggested)
fastapi-todo/
app/
main.py
models.py
crud.py
schemas.py
auth.py
tests/
Dockerfile
requirements.txt
Deliverables
-
Endpoints: Create/List/Update/Delete todos; user auth; protected endpoints.
Module 12 — Docs, OpenAPI customization, and next steps (60 minutes)
Goal
Customize documentation, add examples and operation ids, and learn how to generate client code.
Tips
-
Use
OpenAPImetadata inFastAPI(title=..., description=..., version=...). -
Use
response_model,summary, andtagson endpoints. -
Use
fastapi.openapi.utils.get_openapito customize schema if needed.
Next steps
-
Explore GraphQL integrations (Strawberry / Ariadne), async ORMs (Tortoise), and production monitoring.
Appendix: Useful snippets
Downloadable uvicorn run helper (bash)
# run.sh
export PYTHONPATH=.
uvicorn app.main:app --reload --port 8000
How to add copy & use buttons for each code block in a Markdown-based blog
Include the editor-template.html snippet or server-side render each code block into the structure shown earlier. If your blog generator supports custom HTML blocks (e.g., Hugo/JS), inject the snippet and the code content into the <code> element and call Prism.highlightElement after insertion.
Done — how I used your references
This tutorial was modeled to follow the hands‑on spirit and practical setup of the Visual Studio Code FastAPI tutorial and the ultimate-fastapi-tutorial repository as practical references.
No comments:
Post a Comment