Python 8 min read

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.

MR

Moshiour Rahman

· Updated May 9, 2026

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

FrameworkRequests/SecondRelative Speed
FastAPI65,000+Fastest
Flask15,000Baseline
Django REST12,0000.8x
Express.js55,0000.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

ConceptDescription
FastAPIHigh-performance Python framework
UvicornASGI server for running the app
PydanticData validation with type hints
Swagger UIInteractive API documentation at /docs
ReDocAlternative documentation at /redoc
AsyncNon-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
Is your AI API down right now? Check live status for OpenAI, Claude, Gemini, Groq, and more.
Check status →
MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

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

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.