FastAPI Tutorial Part 1: Introduction and Setup - Build Modern Python APIs
Start your FastAPI journey with this comprehensive guide. Learn installation, create your first API, understand async Python, and explore automatic documentation.
Moshiour Rahman
Advertisement
What is FastAPI?
FastAPI is a modern, high-performance Python web framework for building APIs. Created by Sebastián Ramírez, it has become one of the most popular Python frameworks due to its speed, simplicity, and developer-friendly features.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Welcome to FastAPI!"}
That’s all you need to create a working API. But FastAPI offers much more than simplicity.
Why Choose FastAPI?
Performance Comparison
| Framework | Requests/Second | Relative Speed |
|---|---|---|
| FastAPI | 65,000+ | Fastest |
| Flask | 15,000 | Baseline |
| Django REST | 12,000 | 0.8x |
| Express.js | 55,000 | 0.85x |
FastAPI achieves this performance through:
- Starlette for async web handling
- Pydantic for data validation
- Python type hints for optimization
Key Features
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
# Automatic data validation
class User(BaseModel):
name: str
email: str
age: int
@app.post("/users/")
def create_user(user: User):
# user is automatically validated
return {"user": user, "message": "User created"}
What you get automatically:
- Request validation
- Response serialization
- Interactive API documentation
- Type checking support
- Async/await support
Installation and Setup
Prerequisites
Ensure you have Python 3.8 or higher:
python --version
# Python 3.11.0 or higher recommended
Create Project Structure
# Create project directory
mkdir fastapi-tutorial
cd fastapi-tutorial
# Create virtual environment
python -m venv venv
# Activate virtual environment
# On macOS/Linux:
source venv/bin/activate
# On Windows:
# venv\Scripts\activate
# Install FastAPI with all dependencies
pip install "fastapi[all]"
The [all] option installs:
- uvicorn - ASGI server
- python-multipart - Form data support
- jinja2 - Template engine
- email-validator - Email validation
Project Structure
fastapi-tutorial/
├── venv/
├── app/
│ ├── __init__.py
│ ├── main.py
│ ├── routers/
│ │ └── __init__.py
│ ├── models/
│ │ └── __init__.py
│ └── schemas/
│ └── __init__.py
├── tests/
│ └── __init__.py
└── requirements.txt
Create the structure:
mkdir -p app/routers app/models app/schemas tests
touch app/__init__.py app/main.py
touch app/routers/__init__.py
touch app/models/__init__.py
touch app/schemas/__init__.py
touch tests/__init__.py
Your First FastAPI Application
Basic Application
Create app/main.py:
from fastapi import FastAPI
# Create FastAPI instance
app = FastAPI(
title="My First API",
description="Learning FastAPI from scratch",
version="1.0.0"
)
@app.get("/")
def root():
"""Root endpoint returning welcome message."""
return {"message": "Hello, FastAPI!"}
@app.get("/health")
def health_check():
"""Health check endpoint for monitoring."""
return {"status": "healthy"}
Running the Application
# Run with uvicorn
uvicorn app.main:app --reload
# Output:
# INFO: Uvicorn running on http://127.0.0.1:8000
# INFO: Started reloader process
# INFO: Started server process
# INFO: Waiting for application startup
# INFO: Application startup complete
Command breakdown:
app.main- Python module path (app/main.py)app- FastAPI instance name--reload- Auto-restart on code changes (development only)
Test Your API
# Using curl
curl http://localhost:8000/
# {"message":"Hello, FastAPI!"}
curl http://localhost:8000/health
# {"status":"healthy"}
Or open http://localhost:8000 in your browser.
Automatic API Documentation
FastAPI generates interactive documentation automatically.
Swagger UI
Visit http://localhost:8000/docs:
from fastapi import FastAPI
app = FastAPI(
title="User Management API",
description="""
## User Management System
This API allows you to:
* Create users
* Read user information
* Update user details
* Delete users
""",
version="1.0.0",
contact={
"name": "API Support",
"email": "support@example.com"
}
)
ReDoc Documentation
Visit http://localhost:8000/redoc for alternative documentation style.
Custom Documentation
from fastapi import FastAPI
app = FastAPI(
docs_url="/documentation", # Change Swagger URL
redoc_url="/redocumentation", # Change ReDoc URL
openapi_url="/api/openapi.json" # Change OpenAPI schema URL
)
# Disable documentation in production
app_prod = FastAPI(docs_url=None, redoc_url=None)
HTTP Methods and Routes
GET - Retrieve Data
@app.get("/items")
def get_items():
"""Retrieve all items."""
return {"items": ["item1", "item2", "item3"]}
@app.get("/items/{item_id}")
def get_item(item_id: int):
"""Retrieve a specific item by ID."""
return {"item_id": item_id, "name": f"Item {item_id}"}
POST - Create Data
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
@app.post("/items")
def create_item(item: Item):
"""Create a new item."""
return {"message": "Item created", "item": item}
PUT - Update Data
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
"""Update an existing item."""
return {"item_id": item_id, "updated_item": item}
DELETE - Remove Data
@app.delete("/items/{item_id}")
def delete_item(item_id: int):
"""Delete an item."""
return {"message": f"Item {item_id} deleted"}
PATCH - Partial Update
from typing import Optional
class ItemUpdate(BaseModel):
name: Optional[str] = None
price: Optional[float] = None
@app.patch("/items/{item_id}")
def patch_item(item_id: int, item: ItemUpdate):
"""Partially update an item."""
return {"item_id": item_id, "updates": item.model_dump(exclude_unset=True)}
Async Support
FastAPI supports Python’s async/await syntax for concurrent operations.
Sync vs Async
# Synchronous - blocks during I/O
@app.get("/sync")
def sync_endpoint():
import time
time.sleep(1) # Blocks the entire process
return {"type": "sync"}
# Asynchronous - non-blocking I/O
@app.get("/async")
async def async_endpoint():
import asyncio
await asyncio.sleep(1) # Doesn't block other requests
return {"type": "async"}
When to Use Async
import httpx
from fastapi import FastAPI
app = FastAPI()
# Use async for I/O operations
@app.get("/external-api")
async def call_external_api():
async with httpx.AsyncClient() as client:
response = await client.get("https://api.example.com/data")
return response.json()
# Use sync for CPU-bound operations
@app.get("/compute")
def compute_heavy():
result = sum(i * i for i in range(1000000))
return {"result": result}
Async Database Example
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
# Async database connection
DATABASE_URL = "postgresql+asyncpg://user:pass@localhost/db"
engine = create_async_engine(DATABASE_URL)
@app.get("/users")
async def get_users():
async with AsyncSession(engine) as session:
result = await session.execute("SELECT * FROM users")
return result.fetchall()
Application Configuration
Environment Variables
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "FastAPI Tutorial"
debug: bool = False
database_url: str
api_key: str
class Config:
env_file = ".env"
settings = Settings()
app = FastAPI(title=settings.app_name, debug=settings.debug)
Create .env file:
DATABASE_URL=postgresql://user:pass@localhost/db
API_KEY=your-secret-key
DEBUG=true
Multiple Environments
from functools import lru_cache
class Settings(BaseSettings):
environment: str = "development"
class Config:
env_file = ".env"
@lru_cache()
def get_settings():
return Settings()
# Usage in endpoints
from fastapi import Depends
@app.get("/info")
def info(settings: Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"environment": settings.environment
}
Complete Example Application
Here’s a complete starter application combining everything:
# app/main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
app = FastAPI(
title="Task Manager API",
description="A simple task management API built with FastAPI",
version="1.0.0"
)
# In-memory storage (replace with database later)
tasks_db = {}
task_counter = 0
# Models
class TaskCreate(BaseModel):
title: str
description: Optional[str] = None
completed: bool = False
class Task(TaskCreate):
id: int
created_at: datetime
class TaskUpdate(BaseModel):
title: Optional[str] = None
description: Optional[str] = None
completed: Optional[bool] = None
# Routes
@app.get("/")
def root():
return {"message": "Task Manager API", "docs": "/docs"}
@app.get("/tasks")
def list_tasks():
"""List all tasks."""
return {"tasks": list(tasks_db.values())}
@app.post("/tasks", status_code=201)
def create_task(task: TaskCreate):
"""Create a new task."""
global task_counter
task_counter += 1
new_task = Task(
id=task_counter,
title=task.title,
description=task.description,
completed=task.completed,
created_at=datetime.now()
)
tasks_db[task_counter] = new_task
return new_task
@app.get("/tasks/{task_id}")
def get_task(task_id: int):
"""Get a specific task."""
if task_id not in tasks_db:
raise HTTPException(status_code=404, detail="Task not found")
return tasks_db[task_id]
@app.put("/tasks/{task_id}")
def update_task(task_id: int, task: TaskUpdate):
"""Update a task."""
if task_id not in tasks_db:
raise HTTPException(status_code=404, detail="Task not found")
stored_task = tasks_db[task_id]
update_data = task.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(stored_task, field, value)
return stored_task
@app.delete("/tasks/{task_id}")
def delete_task(task_id: int):
"""Delete a task."""
if task_id not in tasks_db:
raise HTTPException(status_code=404, detail="Task not found")
del tasks_db[task_id]
return {"message": f"Task {task_id} deleted"}
@app.get("/tasks/stats/summary")
def task_stats():
"""Get task statistics."""
total = len(tasks_db)
completed = sum(1 for t in tasks_db.values() if t.completed)
return {
"total": total,
"completed": completed,
"pending": total - completed
}
Test the Application
# Start the server
uvicorn app.main:app --reload
# Create a task
curl -X POST "http://localhost:8000/tasks" \
-H "Content-Type: application/json" \
-d '{"title": "Learn FastAPI", "description": "Complete the tutorial"}'
# List all tasks
curl http://localhost:8000/tasks
# Get task statistics
curl http://localhost:8000/tasks/stats/summary
Requirements File
Create requirements.txt:
fastapi[all]==0.109.0
uvicorn[standard]==0.27.0
pydantic==2.5.3
pydantic-settings==2.1.0
httpx==0.26.0
Install dependencies:
pip install -r requirements.txt
Summary
| Concept | Description |
|---|---|
| FastAPI | High-performance Python framework |
| Uvicorn | ASGI server for running the app |
| Pydantic | Data validation with type hints |
| Swagger UI | Interactive API documentation at /docs |
| ReDoc | Alternative documentation at /redoc |
| Async | Non-blocking I/O with async/await |
Next Steps
In Part 2, we’ll dive deep into Path and Query Parameters - learning how to handle URL parameters, add validation, and create flexible API endpoints.
Series Navigation:
- Part 1: Introduction and Setup (You are here)
- Part 2: Path and Query Parameters
- Part 3: Request Bodies and Pydantic
- Part 4: Response Models and Status Codes
Advertisement
Moshiour Rahman
Software Architect & AI Engineer
Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.
Related Articles
FastAPI Tutorial Part 2: Path and Query Parameters - Complete Guide
Master FastAPI path and query parameters. Learn parameter validation, type conversion, optional parameters, and advanced patterns for building flexible APIs.
PythonFastAPI Tutorial Part 4: Response Models and Status Codes - Control Your API Output
Learn to control FastAPI responses with response models, status codes, and headers. Master data filtering, multiple response types, and proper HTTP semantics.
PythonFastAPI Tutorial: Build Modern Python APIs
Master FastAPI for building high-performance Python APIs. Learn async endpoints, validation, authentication, database integration, and deployment.
Comments
Comments are powered by GitHub Discussions.
Configure Giscus at giscus.app to enable comments.