DEV Community

Alex Spinov
Alex Spinov

Posted on

FastAPI Has a Free API — The Fastest Python Web Framework

FastAPI is the fastest-growing Python web framework — 78K+ GitHub stars, async by default, automatic OpenAPI docs, and type-safe validation. All free and open source.

Why FastAPI?

  • Fastest Python framework — on par with Node.js and Go
  • Automatic API docs — Swagger UI and ReDoc generated from code
  • Type validation — Pydantic v2 validates all inputs automatically
  • Async native — built on ASGI, supports async/await
  • Dependency injection �� clean, testable code
  • Production-ready — used by Microsoft, Netflix, Uber

Quick Start

pip install fastapi uvicorn
Enter fullscreen mode Exit fullscreen mode
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello, FastAPI!"}

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return {"user_id": user_id, "name": "Alice"}

# Run with: uvicorn main:app --reload
# Docs at: http://localhost:8000/docs
Enter fullscreen mode Exit fullscreen mode

Pydantic Models (Auto-Validation)

from pydantic import BaseModel, EmailStr, Field
from datetime import datetime

class CreateUser(BaseModel):
    name: str = Field(min_length=2, max_length=50)
    email: EmailStr
    age: int = Field(ge=18, le=120)
    role: str = Field(default="user", pattern="^(admin|user|moderator)$")

class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    created_at: datetime

@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: CreateUser):
    # user is already validated — invalid data returns 422 automatically
    db_user = await db.create_user(**user.model_dump())
    return db_user
Enter fullscreen mode Exit fullscreen mode

Send invalid data? FastAPI returns detailed error:

{
  "detail": [
    {
      "loc": ["body", "email"],
      "msg": "value is not a valid email address",
      "type": "value_error.email"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Query Parameters

from typing import Optional
from enum import Enum

class SortOrder(str, Enum):
    asc = "asc"
    desc = "desc"

@app.get("/users")
async def list_users(
    page: int = 1,
    limit: int = Field(default=10, le=100),
    search: Optional[str] = None,
    sort: SortOrder = SortOrder.desc,
    active: bool = True,
):
    # All parameters are validated and typed automatically
    query = db.users.filter(active=active)
    if search:
        query = query.filter(name__contains=search)
    return await query.order_by(sort.value).offset((page-1)*limit).limit(limit).all()
Enter fullscreen mode Exit fullscreen mode

Dependency Injection

from fastapi import Depends, HTTPException, Header

# Database dependency
async def get_db():
    db = Database()
    try:
        yield db
    finally:
        await db.close()

# Auth dependency
async def get_current_user(authorization: str = Header()):
    token = authorization.replace("Bearer ", "")
    user = await verify_token(token)
    if not user:
        raise HTTPException(status_code=401, detail="Invalid token")
    return user

# Admin dependency (chains with auth)
async def require_admin(user = Depends(get_current_user)):
    if user.role != "admin":
        raise HTTPException(status_code=403, detail="Admin required")
    return user

@app.get("/admin/users")
async def admin_list_users(
    admin = Depends(require_admin),
    db = Depends(get_db),
):
    return await db.users.all()

@app.get("/me")
async def my_profile(user = Depends(get_current_user)):
    return user
Enter fullscreen mode Exit fullscreen mode

File Upload

from fastapi import UploadFile, File

@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
    contents = await file.read()
    return {
        "filename": file.filename,
        "size": len(contents),
        "content_type": file.content_type,
    }

@app.post("/upload-multiple")
async def upload_multiple(files: list[UploadFile] = File(...)):
    return [{"filename": f.filename, "size": f.size} for f in files]
Enter fullscreen mode Exit fullscreen mode

WebSockets

from fastapi import WebSocket, WebSocketDisconnect

connected_clients: list[WebSocket] = []

@app.websocket("/ws/chat")
async def chat(websocket: WebSocket):
    await websocket.accept()
    connected_clients.append(websocket)

    try:
        while True:
            message = await websocket.receive_text()
            # Broadcast to all clients
            for client in connected_clients:
                await client.send_text(f"User: {message}")
    except WebSocketDisconnect:
        connected_clients.remove(websocket)
Enter fullscreen mode Exit fullscreen mode

Background Tasks

from fastapi import BackgroundTasks

async def send_notification(email: str, message: str):
    # This runs after the response is sent
    await send_email(email, message)
    await log_notification(email)

@app.post("/orders")
async def create_order(order: OrderCreate, background_tasks: BackgroundTasks):
    db_order = await save_order(order)

    # Schedule background work
    background_tasks.add_task(send_notification, order.email, f"Order {db_order.id} confirmed!")

    return db_order  # Response sent immediately
Enter fullscreen mode Exit fullscreen mode

Automatic OpenAPI Docs

FastAPI generates interactive API documentation at:

  • Swagger UI: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc
  • OpenAPI JSON: http://localhost:8000/openapi.json

No configuration needed. Add docstrings and they show up in docs:

@app.post("/users", tags=["users"], summary="Create a new user")
async def create_user(user: CreateUser):
    """
    Create a new user with the following fields:

    - **name**: User's display name (2-50 chars)
    - **email**: Valid email address
    - **age**: Must be 18+
    """
    ...
Enter fullscreen mode Exit fullscreen mode

FastAPI vs Django vs Flask vs Express

Feature FastAPI Django Flask Express
Speed Fastest (Python) Medium Medium Fast
Async Native Optional No Native
Validation Automatic (Pydantic) Forms/DRF Manual Manual
API docs Automatic DRF plugin Plugin Plugin
ORM Any (SQLAlchemy) Built-in Any Any
Auth Dependency injection Built-in Plugin Plugin
Learning curve Low High Low Low

Need to scrape data from any website and get it in structured JSON? Check out my web scraping tools on Apify — no coding required, results in minutes.

Have a custom data extraction project? Email me at spinov001@gmail.com — I build tailored scraping solutions for businesses.

Top comments (0)