Skip to main content

Getting Started with FastAPI

Learn how to install FastAPI, create your first API, and understand the basic concepts that make FastAPI powerful and easy to use.

Installation

Prerequisites

  • Python 3.7 or higher
  • pip (Python package installer)
  • Virtual environment (recommended)

Basic Installation

Install FastAPI and an ASGI server (Uvicorn) to run your application:

pip install fastapi
pip install "uvicorn[standard]"

Optional Dependencies

For specific features, you may want to install additional packages:

# For email validation and other Pydantic features
pip install "pydantic[email]"

# For serving static files and templating
pip install jinja2 python-multipart

# For testing
pip install httpx pytest

Complete Installation

For a full development setup with all optional dependencies:

pip install "fastapi[all]"

This includes Uvicorn with all features, Pydantic with validation, and testing dependencies.

Your First FastAPI Application

Hello World

Create a file called main.py:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
return {"message": "Hello World"}

Running the Application

Start the development server:

uvicorn main:app --reload

Parameters explained:

  • main: the Python file (main.py)
  • app: the FastAPI instance in main.py
  • --reload: auto-restart on code changes (development only)

Testing Your API

Open your browser and navigate to:

Path Operations

Multiple Endpoints

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
return {"message": "Hello World"}

@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}

@app.post("/items")
def create_item(name: str, price: float):
return {"name": name, "price": price}

HTTP Methods

FastAPI supports all standard HTTP methods:

@app.get("/items")      # Read items
@app.post("/items") # Create item
@app.put("/items/{id}") # Update entire item
@app.patch("/items/{id}") # Partial update
@app.delete("/items/{id}") # Delete item

Path Parameters

Define variable parts of the URL path:

@app.get("/users/{user_id}")
def read_user(user_id: int):
return {"user_id": user_id}

@app.get("/users/{user_id}/items/{item_id}")
def read_user_item(user_id: int, item_id: str):
return {"user_id": user_id, "item_id": item_id}

Type Validation

FastAPI automatically validates path parameter types:

@app.get("/items/{item_id}")
def read_item(item_id: int):
# If item_id is not an integer, FastAPI returns 422 error
return {"item_id": item_id}

Predefined Values (Enums)

Use Python Enums for predefined path values:

from enum import Enum

class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"

@app.get("/models/{model_name}")
def get_model(model_name: ModelName):
if model_name == ModelName.alexnet:
return {"model": model_name, "message": "Deep Learning FTW!"}

if model_name.value == "lenet":
return {"model": model_name, "message": "LeCNN all the images"}

return {"model": model_name, "message": "Have some residuals"}

Query Parameters

Add optional or required query parameters:

from typing import Optional

@app.get("/items")
def read_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}

@app.get("/search")
def search(q: Optional[str] = None, page: int = 1):
if q:
return {"query": q, "page": page}
return {"message": "No query provided", "page": page}

Multiple Path and Query Parameters

@app.get("/users/{user_id}/items")
def read_user_items(
user_id: int,
skip: int = 0,
limit: int = 10,
q: Optional[str] = None
):
results = {"user_id": user_id, "skip": skip, "limit": limit}
if q:
results["q"] = q
return results

Request Body

Use Pydantic models for request bodies:

from pydantic import BaseModel
from typing import Optional

class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None

@app.post("/items")
def create_item(item: Item):
item_dict = item.dict()
if item.tax:
price_with_tax = item.price + item.tax
item_dict["price_with_tax"] = price_with_tax
return item_dict

Request + Path + Query Parameters

Combine all parameter types:

@app.put("/items/{item_id}")
def update_item(
item_id: int, # Path parameter
item: Item, # Request body
q: Optional[str] = None # Query parameter
):
result = {"item_id": item_id, **item.dict()}
if q:
result["q"] = q
return result

Automatic Documentation

FastAPI automatically generates interactive API documentation:

Swagger UI

Access at /docs - provides:

  • Interactive API testing
  • Request/response examples
  • Parameter descriptions
  • Model schemas

ReDoc

Access at /redoc - provides:

  • Clean, organized documentation
  • Searchable API reference
  • Detailed model documentation
  • Three-panel layout

OpenAPI Schema

Raw OpenAPI schema available at /openapi.json:

# Access programmatically
import requests
response = requests.get("http://localhost:8000/openapi.json")
schema = response.json()

Application Configuration

Metadata and Documentation

Configure your API metadata:

from fastapi import FastAPI

app = FastAPI(
title="My API",
description="A comprehensive API for managing items",
version="1.0.0",
terms_of_service="http://example.com/terms/",
contact={
"name": "API Support",
"email": "support@example.com",
},
license_info={
"name": "MIT",
"url": "https://opensource.org/licenses/MIT",
},
)

Tags for Organization

Group related endpoints with tags:

@app.get("/users/", tags=["users"])
def read_users():
return [{"name": "Alice"}, {"name": "Bob"}]

@app.get("/items/", tags=["items"])
def read_items():
return [{"name": "Item 1"}, {"name": "Item 2"}]

Response Handling

Custom Status Codes

from fastapi import status

@app.post("/items", status_code=status.HTTP_201_CREATED)
def create_item(item: Item):
return item

@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_item(item_id: int):
return None

Response Models

Define the structure of responses:

class ItemResponse(BaseModel):
name: str
price: float

@app.post("/items", response_model=ItemResponse)
def create_item(item: Item):
# Even if Item has more fields, only ItemResponse fields are returned
return item

Error Handling

HTTP Exceptions

from fastapi import HTTPException

@app.get("/items/{item_id}")
def read_item(item_id: int):
if item_id not in items_db:
raise HTTPException(
status_code=404,
detail="Item not found"
)
return items_db[item_id]

Custom Exception Handlers

from fastapi import Request
from fastapi.responses import JSONResponse

class CustomException(Exception):
def __init__(self, name: str):
self.name = name

@app.exception_handler(CustomException)
def custom_exception_handler(request: Request, exc: CustomException):
return JSONResponse(
status_code=418,
content={"message": f"Oops! {exc.name} did something wrong."}
)

Project Structure

For larger applications, organize your code:

myapp/
├── main.py
├── models/
│ ├── __init__.py
│ └── item.py
├── routers/
│ ├── __init__.py
│ ├── users.py
│ └── items.py
└── dependencies.py

Using Routers

routers/items.py:

from fastapi import APIRouter

router = APIRouter(
prefix="/items",
tags=["items"]
)

@router.get("/")
def read_items():
return [{"name": "Item 1"}]

@router.get("/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}

main.py:

from fastapi import FastAPI
from routers import items, users

app = FastAPI()

app.include_router(items.router)
app.include_router(users.router)

Development Tips

Hot Reload

Use --reload during development for automatic reloading:

uvicorn main:app --reload --host 0.0.0.0 --port 8000

Debug Mode

Enable debug logging:

import logging

logging.basicConfig(level=logging.DEBUG)

IDE Support

FastAPI works great with:

  • VS Code: Python extension + Pylance for type checking
  • PyCharm: Professional edition has excellent FastAPI support
  • Vim/Neovim: with Python LSP (pyright or pylsp)

Next Steps

Now that you understand the basics:

  1. Request Handling: Learn advanced request validation and parsing
  2. Response Models: Master response schemas and serialization
  3. Dependencies: Understand FastAPI's powerful dependency injection
  4. Database Integration: Connect to databases with SQLAlchemy
  5. Authentication: Implement OAuth2, JWT, and security features
  6. Testing: Write comprehensive tests for your API
  7. Deployment: Deploy to production with proper configuration

Common Patterns

Health Check Endpoint

@app.get("/health")
def health_check():
return {"status": "healthy"}

Versioned API

@app.get("/v1/items")
def read_items_v1():
return [{"name": "Item 1"}]

@app.get("/v2/items")
def read_items_v2():
return [{"id": 1, "name": "Item 1", "new_field": "value"}]

CORS Configuration

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

You're now ready to build FastAPI applications! Start with simple endpoints and gradually add more features as you become comfortable with the framework.