Mario Brusarosco

fast api

In the ground since Wed Feb 24 2021

Last watered inWed Feb 24 2021

Related Topics

Fast API

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.8+ based on standard Python type hints.

Benefits

  • Fast: Very high performance, on par with NodeJS and Go.
  • Type-checked (catches errors before runtime)
  • Automatic API documentation

Anatomy of a FastAPI application

1@router.post("/", response_model=User)
2def create_user(
3 user_in: UserCreate,
4 db: Session = Depends(get_db)
5):
6
7This is a decorator that tells FastAPI this function handles POST requests
8```python
9@router.post("/")
1response_model=User:

Defines what the API will return (automatic validation!)

1user_in: UserCreate

Input validation using Pydantic models

1Depends(get_db)

Dependency injection (we'll cover this later)

Return values

  • FastAPI automatically converts Python dictionaries to JSON
  • Content-Type header will be application/json
1return {"message": "User created successfully"}

Path parameters

1@router.get("/users/{user_id}")

Synchronous vs Asynchronous in FastAPI

FastAPI supports both synchronous and asynchronous endpoints. Understanding the difference is crucial for building efficient APIs.

Synchronous (Sync) Endpoints

1@app.get("/users")
2def get_users():
3 # Blocks here until database returns
4 result = db.query(User).all()
5 return result

Characteristics:

  • Executes code line by line
  • Waits for each operation to complete
  • Blocks the thread while waiting
  • Simpler to understand and debug

Asynchronous (Async) Endpoints

1@app.get("/users")
2async def get_users():
3 # Releases thread while waiting for database
4 result = await db.query(User).all()
5 return result

Characteristics:

  • Can handle multiple operations concurrently
  • Doesn't block while waiting for I/O
  • More efficient for I/O-bound operations
  • Uses async/await syntax

When to Use Each

Use Sync when:

  • Doing CPU-intensive work
  • Using libraries that don't support async
  • Code is simple and doesn't involve waiting
1@app.get("/calculate")
2def calculate_something():
3 result = heavy_computation() # CPU-intensive
4 return {"result": result}

Use Async when:

  • Making HTTP requests
  • Database operations (with async driver)
  • File I/O operations
  • Handling websockets
1@app.get("/fetch-external")
2async def fetch_external_api():
3 async with httpx.AsyncClient() as client:
4 response = await client.get("https://api.example.com")
5 return response.json()

Common Pitfalls

  1. Blocking I/O in Async Functions (Bad)
1@app.get("/slow")
2async def slow_endpoint():
3 time.sleep(1) # Blocks the thread!
4 return {"message": "Done"}
  1. Proper Async Usage (Good)
1@app.get("/fast")
2async def fast_endpoint():
3 await asyncio.sleep(1) # Releases thread while waiting
4 return {"message": "Done"}

API Documentation

FastAPI provides automatic interactive API documentation using:

Swagger UI

  • Available at /docs
  • Interactive documentation
  • Try out API endpoints directly
  • Shows request/response schemas

ReDoc

  • Available at /redoc
  • Alternative documentation view
  • Better for reading and sharing

How Documentation is Generated

FastAPI uses your:

  1. Function names and docstrings
  2. Type hints
  3. Pydantic models
  4. Path operation decorators

Example with full documentation:

1from typing import List
2from pydantic import BaseModel
3
4class Item(BaseModel):
5 name: str
6 description: str | None = None
7 price: float
8
9@app.get("/items/", response_model=List[Item], tags=["items"])
10async def get_items(skip: int = 0, limit: int = 10):
11 """
12 Retrieve items with pagination.
13
14 - **skip**: Number of items to skip
15 - **limit**: Maximum number of items to return
16 """
17 return items[skip : skip + limit]

This generates:

  • Endpoint description
  • Request parameters
  • Response model
  • Example values
  • Try it out functionality

Enhancing Documentation

  1. Tags - Group endpoints:
1@app.get("/users/", tags=["users"])
  1. Summary and Description:
1@app.post("/users/",
2 summary="Create a user",
3 description="Create a new user with the provided information")
  1. Response Description:
1@app.get("/users/{user_id}",
2 response_description="The found user")
  1. Status Codes:
1@app.post("/items/", status_code=201)