Learning Path: FastAPI Onboarding — Build, Test, and Deploy a Secure REST Service
One-line learning outcome: By completing this path you'll be able to design, implement, test, harden, and deploy a production-ready REST API using FastAPI, with CI and basic observability.
Estimated total time: 12–16 hours (split across 5 modules)
Audience: Junior to mid-level developers, bootcamp learners, new hires, and mentors designing onboarding tracks.
Prerequisites
- Comfort with Python 3.8+ and virtual environments
- Basic HTTP/REST knowledge
- Familiarity with Git and GitHub
- Command line comfort (macOS/Linux/Windows WSL)
Module overview
- Module 1 — Project Setup & Minimal CRUD API (2–3 hrs, Easy)
- Module 2 — Validation, Dependency Injection & Documentation (2 hrs, Easy→Medium)
- Module 3 — Authentication, Authorization & Security Best Practices (3 hrs, Medium)
- Module 4 — Testing, Fixtures & CI (3–4 hrs, Medium)
- Module 5 — Containerization & Deploying to a Cloud Host (2–3 hrs, Medium)
Module 1: Project Setup & Minimal CRUD API
Objectives: Create project skeleton, implement basic routes, run local server, auto-generated docs.
Time: 2–3 hours • Difficulty: Easy
Narrative: Start small: scaffold a FastAPI app, add an in-memory store, and expose CRUD endpoints. Observe OpenAPI docs.
Hands-on lab (stepwise)
- Create project folder & venv
mkdir fastapi-onboarding && cd fastapi-onboarding
python -m venv .venv
source .venv/bin/activate # or .\.venv\Scripts\activate on Windows
pip install fastapi uvicorn
- Create
app/main.pywith minimal APIfrom fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): id: int name: str store = {} @app.post('/items') def create_item(item: Item): store[item.id] = item return item @app.get('/items/{item_id}') def read_item(item_id: int): return store.get(item_id, {'error':'not found'}) - Run server and visit docs
uvicorn app.main:app --reload
# Visit http://127.0.0.1:8000/docs — expect interactive OpenAPI UI
Exercises
- Add an update (PUT) and delete (DELETE) endpoint. (Easy)
- Persist data to a JSON file so server restarts keep data. (Medium)
- Create a small README with API examples and curl commands. (Easy)
Checkpoint: You can start the server and use /docs to run POST and GET requests returning expected JSON.
Mentor tip: Encourage pair programming for the first POST/GET so learners see live docs and schema behaviour.
Module 2: Validation, Dependency Injection & Documentation
Objectives: Use Pydantic models for request/response validation, implement dependency injection for shared services, and improve docs.
Time: 2 hours • Difficulty: Easy → Medium
Hands-on lab
- Enhance Pydantic models with field constraints
from pydantic import Field class Item(BaseModel): id: int = Field(..., ge=1) name: str = Field(..., min_length=2) - Add a dependency for a simple logger
from fastapi import Depends def get_logger(): def log(msg): print(msg) return {'log': log} @app.post('/items') def create_item(item: Item, logger=Depends(get_logger)): logger['log'](f"Creating {item}") store[item.id] = item return item
Exercises
- Add response models to hide internal fields. (Medium)
- Write OpenAPI metadata for the app and tag endpoints. (Easy)
Checkpoint: Requests with invalid payloads return 422 with clear messages and docs reflect models.
Module 3: Authentication, Authorization & Security Best Practices
Objectives: Add OAuth2 password flow (or API key), secure endpoints, rate-limit concept, and basic headers.
Time: 3 hrs • Difficulty: Medium
Hands-on lab (snippet)
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.post('/token')
def login(form_data: OAuth2PasswordRequestForm = Depends()):
# demo: return a fake token
return {'access_token': 'fake-token', 'token_type': 'bearer'}
@app.get('/users/me')
def read_me(token: str = Depends(oauth2_scheme)):
if token != 'fake-token':
raise HTTPException(401)
return {'username': 'demo'}
Exercises
- Replace fake token with JWT signed using a secret. (Medium)
- Implement a roles-based decorator that blocks non-admin users. (Medium)
Checkpoint: Protected route returns 401 without token and returns user info with valid token.
Mentor tip: Stress threat models: what happens if tokens leak? Discuss token rotation and secrets management.
Module 4: Testing, Fixtures & CI
Objectives: Write unit and integration tests using pytest and TestClient; add GitHub Actions CI to run tests on push.
Time: 3–4 hrs • Difficulty: Medium
Hands-on lab
- Install test deps and create tests
pip install pytest httpx
# tests/test_api.py
from fastapi.testclient import TestClient from app.main import app client = TestClient(app) def test_create_and_read(): res = client.post('/items', json={'id':1,'name':'T'}) assert res.status_code == 200 res2 = client.get('/items/1') assert res2.json()['name']=='T' - Add a simple GitHub Actions workflow
.github/workflows/ci.ymlname: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- run: python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt && pytest -q
Exercises
- Write a test for authentication flow and a fixture for an auth token. (Medium)
- Configure CI to run linting and type checks (flake8/mypy). (Medium)
Checkpoint: Tests pass locally and CI runs green on a GitHub push.
Module 5: Containerization & Deploy to a Cloud Host
Objectives: Dockerize the app, push image to a registry, deploy to a simple host (e.g., Render, Heroku, or Cloud Run).
Time: 2–3 hrs • Difficulty: Medium
Hands-on lab (Dockerfile)
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "$PORT"]
# build and run
docker build -t fastapi-onboarding:dev .
docker run -p 8000:8000 fastapi-onboarding:dev
# visit http://localhost:8000/docs
Exercises
- Deploy to Render or Cloud Run and configure environment secrets. (Medium)
- Add health and readiness endpoints and configure a liveness probe. (Medium)
Checkpoint: Live endpoint responds in production host and CI pipeline builds and pushes the image.
Assessment rubric (suggested)
- Functionality (40%): endpoints work, error cases handled
- Tests & CI (20%): tests cover core paths, CI runs on push
- Security & Best Practices (20%): auth, secrets, input validation
- Documentation & Observability (10%): README, OpenAPI, logs
- Deployment (10%): containerization and live deployment
Sample solution sketches (kept separate from exercises)
Check sample branch on repo: /solutions/module1-5. Sketches include a minimal JWT auth util, pytest fixtures for client and token, Dockerfile and GitHub Actions YAML.
Alternative implementations & trade-offs
- Flask + Flask-RESTful: smaller ecosystem familiarity for some teams, but less built-in validation and docs.
- Node.js + Express: wider JavaScript hiring pool, but requires extra libraries for validation and OpenAPI generation.
Recommended reading & tooling
- FastAPI docs: https://fastapi.tiangolo.com/
- Pydantic docs, Uvicorn, pytest, GitHub Actions docs
- Optional: Sentry for errors, Prometheus/Grafana for metrics
Common stumbling blocks & debugging hints
- 422 errors: check Pydantic model shape and content-types (use JSON). Use /docs to view schemas.
- Dependency injection order: ensure dependencies return expected types.
- CI failures: replicate GitHub Actions environment locally using the same Python version.
Accessibility considerations
- Ensure OpenAPI descriptions are concise and screen-reader friendly.
- Include example cURL commands and provide captions/transcripts for any screencast demos.
Finish with a small capstone: add a single-page team dashboard that consumes your API and shows item counts, with a README explaining how to run everything locally and in CI (2–4 hours).