A comprehensive, hands-on learning project for mastering FastAPI - a modern, fast (high-performance) web framework for building APIs with Python 3.7+ based on standard Python type hints.
- Introduction
- Features
- Project Structure
- Installation & Setup
- Running the Application
- File Descriptions
- Core FastAPI Concepts
- API Endpoints
- Testing the API
- Best Practices
- Common Issues
- Resources
FastAPI is a modern, fast web framework for building APIs with Python. This project serves as a complete learning resource, progressing from basic concepts to advanced patterns like CRUD operations, routers, and production-ready code structure.
- ⚡ Fast: Very high performance, on par with NodeJS and Go
- 🚀 Fast to code: Increase development speed by 200-300%
- 🐛 Fewer bugs: Reduce human-induced errors by about 40%
- 💡 Intuitive: Great editor support with autocomplete
- 📝 Automatic docs: Interactive API documentation (Swagger UI & ReDoc)
- 🔒 Type safe: Based on Python type hints
- 🎯 Standards-based: Based on OpenAPI and JSON Schema
This project demonstrates:
- ✅ Complete CRUD operations (Create, Read, Update, Delete)
- ✅ Pydantic models for data validation and serialization
- ✅ APIRouter for modular code organization
- ✅ HTML serving alongside JSON APIs
- ✅ Error handling with proper HTTP status codes
- ✅ Async/await for concurrent request handling
- ✅ Automatic API documentation (Swagger UI and ReDoc)
- ✅ File-based JSON database (for learning purposes)
- ✅ Type hints for better code quality and IDE support
- ✅ CORS middleware configuration
- ✅ Health check endpoints for monitoring
First_steps_Fastapi/
├── main.py # Main application entry point with routers
├── note_1.py # Basics: First endpoints, path/query params
├── note_2.py # HTML responses and static content
├── note_3.py # User CRUD: GET, POST, PUT
├── nota_4.py # Complete CRUD: GET, POST, PUT, DELETE
├── note_5.py # Fun router demonstrating APIRouter
├── README.md # This file
├── html/
│ └── html_prueba.html # Sample HTML page
└── json/
├── json_for_pydantic.json # Structured user data (database)
└── json_unstructurated.json # Example of unstructured data
- Python 3.7 or higher
- pip (Python package manager)
- Clone or navigate to the project directory
cd First_steps_Fastapi- Create a virtual environment (recommended)
python -m venv venv
# Activate on Linux/Mac:
source venv/bin/activate
# Activate on Windows:
venv\Scripts\activate- Install dependencies
pip install fastapi uvicorn pydanticOr if you have a requirements.txt:
pip install -r requirements.txtDevelopment mode (with auto-reload):
uvicorn main:app --reloadProduction mode:
uvicorn main:app --host 0.0.0.0 --port 8000fastapi dev main.py # Development with auto-reload
fastapi run main.py # Production modeEach note_*.py file can be run independently:
uvicorn note_1:app --reload # Basic concepts
uvicorn note_2:app --reload # HTML serving
uvicorn note_3:app --reload # User CRUD (no DELETE)
uvicorn nota_4:app --reload # Complete CRUDOnce running, visit:
- Home: http://localhost:8000
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
- OpenAPI JSON: http://localhost:8000/openapi.json
Stop the server: Press CTRL + C
Purpose: Main application entry point demonstrating production-ready structure.
Features:
- Application configuration and metadata
- CORS middleware setup
- Router integration (includes routers from other modules)
- Custom exception handlers
- Startup/shutdown events
- Beautiful welcome page with links
Key concepts: Application lifecycle, middleware, modular architecture
Run: uvicorn main:app --reload
Purpose: Introduction to FastAPI basics
What you'll learn:
- Creating a FastAPI instance
- Defining GET endpoints
- Path parameters (
/hello/{name}) - Query parameters (
/search?query=something) - Multiple parameters
- Return types and type hints
- Async functions
Endpoints:
GET /- Welcome messageGET /hello/{name}- Path parameter exampleGET /search?query=...&limit=10- Query parametersGET /users/{user_id}/posts/{post_id}- Multiple path paramsGET /health- Health check
Run: uvicorn note_1:app --reload
Purpose: Serving HTML content with FastAPI
What you'll learn:
- Using
HTMLResponseclass - Reading HTML from files
- Inline HTML generation
- Dynamic HTML with parameters
- Mixing JSON and HTML endpoints
- Error handling for missing files
Endpoints:
GET /- Serve HTML from fileGET /inline- Inline HTML exampleGET /welcome/{name}- Dynamic HTML generationGET /api/info- JSON API alongside HTMLGET /health- Health check
Run: uvicorn note_2:app --reload
Purpose: User management API (CRUD without DELETE)
What you'll learn:
- Pydantic models for data validation
- GET endpoints (all users, single by ID)
- POST endpoint (create user)
- PUT endpoint (update user)
- Response models
- Error handling with HTTPException
- Working with JSON files
- Helper functions for DRY code
- Validation with Field constraints
Endpoints:
GET /- HTML pageGET /users- List all usersGET /users/{id}- Get specific userPOST /users- Create new userPUT /users/{id}- Update user completelyGET /health- Health check
Key Features:
- Comprehensive input validation
- Duplicate checking (ID and email)
- Proper status codes (200, 201, 400, 404, 500)
- Helper functions for file operations
- Detailed error messages
Run: uvicorn note_3:app --reload
Purpose: Complete user management API (Full CRUD)
What you'll learn:
- All CRUD operations (Create, Read, Update, Delete)
- DELETE HTTP method
- Router integration (includes note_5 router)
- API statistics endpoint
- Enhanced health checks
- Complete production-ready structure
Endpoints:
GET /- HTML pageGET /users- List all usersGET /users/{id}- Get specific userPOST /users- Create new user (201 status)PUT /users/{id}- Update user completelyDELETE /users/{id}- Delete userGET /health- Health check with statsGET /stats- API statisticsGET /fun/*- Fun endpoints (from note_5)
Key Features
- Enumeration: Uses
enumerate()to track index position for safe removal. - File Persistence: Updates JSON file immediately after deletion.
- Error Handling: Returns 404 if user doesn't exist.
- Response Format: Returns a JSON object with deletion confirmation.
mi_api/
├── main.py # Main entry point
├── note_3.py # User endpoints (GET, POST)
├── nota_4.py # User endpoints (GET, POST, DELETE)
├── html/
│ └── html_prueba.html
└── json/
└── json_for_pydantic.json
main.py→ instantiates FastAPI and includes routers.note_3.py→ defines user endpoints (GET all, GET by ID, POST create).nota_4.py→ defines user endpoints with DELETE functionality (full CRUD).html/→ static HTML files.json/→ stores JSON data for users.
| Status Code | Description |
|---|---|
| 200 | OK - Successful request |
| 201 | Created - Resource created |
| 204 | No Content - Successful but no response body |
| 400 | Bad Request - Invalid input |
| 401 | Unauthorized - Authentication required |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource not found |
| 500 | Internal Server Error - Server error |
In FastAPI, a router (APIRouter) is a way to organize your endpoints (routes) into logical, reusable modules. Think of a router as a mini FastAPI app that you can plug into your main app. This is very useful when your project grows, because it keeps the code clean and modular.
- Modularity – Instead of putting all endpoints in
main.py, you can separate them by functionality (e.g., users, products, orders, fun endpoints). - Scalability – Multiple developers can work on different routers at the same time without conflicts.
- Organization in Documentation – Using
tagswith routers groups endpoints automatically in Swagger UI (/docs), making it easier to read. - Prefixes – You can add a common URL prefix to all endpoints in the router (e.g.,
/users), avoiding repeating paths.
Example structure without routers (messy for large apps):
@app.get("/users")
async def get_users(): ...
@app.post("/users")
async def create_user(): ...
@app.delete("/users/{id}"): ...
@app.get("/orders"): ...
@app.post("/orders"): ...
# All endpoints in main.py → hard to maintainWith routers (clean and modular):
main.py -> FastAPI app
routers/
├─ note_3.py -> users router
├─ note_4.py -> users with delete
├─ note_5.py -> fun example router
Each router handles its own endpoints and then is included in the main app:
from fastapi import FastAPI
import note_3, note_4, note_5
app = FastAPI()
app.include_router(note_3.router)
app.include_router(note_4.router)
app.include_router(note_5.router)This way, main.py stays small and readable, while each module is responsible for its part of the API.
Purpose: Fun router demonstrating APIRouter concepts
What you'll learn:
- Creating an APIRouter
- Using prefix and tags
- Exporting routers for use in other files
- Simple, focused examples without complex logic
- Query parameter usage
Endpoints (all under /fun prefix):
GET /fun/hello?name=...- Personalized greetingGET /fun/random-number?min=0&max=100- Random number generatorGET /fun/color- Random color picker
Key Concepts:
- Router isolation (can be reused in different apps)
- Prefix grouping (
/fun/*) - Tags for documentation organization
- Import and include in other apps
Use in other files:
from note_5 import router as fun_router
app.include_router(fun_router)| Method | Purpose | FastAPI Decorator |
|---|---|---|
| GET | Read/retrieve a resource | @app.get() |
| POST | Create a new resource | @app.post() |
| PUT | Update a resource completely | @app.put() |
| PATCH | Partially update a resource | @app.patch() |
| DELETE | Delete a resource | @app.delete() |
| OPTIONS | Describe communication options | @app.options() |
| HEAD | Retrieve headers without body | @app.head() |
Pydantic models provide data validation, serialization, and documentation automatically.
from pydantic import BaseModel, Field
from typing import Optional
class User(BaseModel):
id: int = Field(..., description="Unique ID", gt=0)
username: str = Field(..., min_length=3, max_length=50)
email: str = Field(..., description="Email address")
age: Optional[int] = Field(None, ge=0, le=150)
is_active: bool = Field(True)
roles: Optional[list[str]] = NoneBenefits:
- ✅ Automatic validation
- ✅ Type safety
- ✅ Auto-generated JSON schema
- ✅ IDE autocomplete support
- ✅ Serialization to/from JSON
- ✅ Documentation generation
Use response_model to define what FastAPI returns:
@app.post("/users", response_model=User, status_code=201)
async def create_user(user: User):
# Save user...
return userCommon status codes used in this project:
| Code | Constant | Meaning | When to Use |
|---|---|---|---|
| 200 | HTTP_200_OK |
Success | Successful GET, PUT, DELETE |
| 201 | HTTP_201_CREATED |
Created | Resource successfully created (POST) |
| 400 | HTTP_400_BAD_REQUEST |
Bad Request | Invalid input, validation error |
| 404 | HTTP_404_NOT_FOUND |
Not Found | Resource doesn't exist |
| 500 | HTTP_500_INTERNAL_SERVER_ERROR |
Server Error | Server/application error |
APIRouter allows organizing endpoints into logical modules.
from fastapi import APIRouter
router = APIRouter(prefix="/users", tags=["Users"])
@router.get("/")
async def list_users():
return {"users": []}
@router.post("/")
async def create_user(user: User):
return userBenefits:
- Modularity
- Reusability
- Team collaboration
- Better documentation
- Code organization
Created as a comprehensive learning resource for mastering FastAPI, from basics to production-ready code.
Happy Learning! 🚀
Key points about note_5.py:
- APIRouter creation
from fastapi import APIRouter
router = APIRouter(prefix="/fun", tags=["Fun"])prefix="/fun"→ every endpoint in this router will start with/fun(e.g.,/fun/hello).tags=["Fun"]→ groups the endpoints under "Fun" in the Swagger documentation (/docs).
- Endpoints in the router
/fun/hello→ returns a fun greeting./fun/random-number→ returns a random number between min and max./fun/color→ returns a random color.
These endpoints are deliberately simple and “silly” to focus on the router mechanics, not business logic.
- Integration with main app
from fastapi import FastAPI
import note_5
app = FastAPI()
app.include_router(note_5.router)include_routerconnects the router to the main app.- All endpoints in
note_5are now available under/fun/....
- Benefits demonstrated
- Clean separation of functionality: Fun endpoints are in
note_5.py, user endpoints innote_3.py/note_4.py. - Easy to extend: If you want a
products.pyrouter later, just create a new router andinclude_routerit. - Easy documentation: Swagger UI automatically groups routes by
tags.
- The big picture
Routers are not mandatory in FastAPI, but they become extremely useful as soon as your project grows beyond a few endpoints. They allow you to:
- Organize your code logically
- Reuse modules in different apps
- Collaborate with others without merge conflicts
- Keep the main app lightweight
Think of a router as a self-contained mini-API. You define endpoints in it, and then attach it to your main FastAPI app.