Skip to main content

FastAPI Global Dependencies

Introduction

In FastAPI, dependencies are a powerful feature that enables code reuse, separation of concerns, and efficient implementation of common functionalities like authentication, database connections, or validation. While we've explored how to apply dependencies to specific endpoints, FastAPI also allows you to apply dependencies globally across your entire application.

Global dependencies execute for every request to your API, making them perfect for implementing consistent behaviors like:

  • Authentication checks
  • Request logging
  • Performance monitoring
  • User tracking
  • Cross-cutting validations

In this tutorial, we'll explore how to set up and use global dependencies in FastAPI applications, and we'll discuss common use cases and best practices.

Understanding Global Dependencies

Global dependencies in FastAPI are dependencies that run for every request to your application. They're useful when you need to apply the same logic or validation across multiple routes without repeating yourself.

How Global Dependencies Differ from Regular Dependencies

Regular DependenciesGlobal Dependencies
Applied to specific endpointsApplied to all endpoints
Defined in the route decoratorDefined when creating the FastAPI app
Optional for specific routesExecuted for every request

Setting Up Global Dependencies

Basic Structure

To add global dependencies to your FastAPI application, use the dependencies parameter when creating your FastAPI app instance:

python
from fastapi import Depends, FastAPI

async def verify_token(x_token: str = Header(...)):
if x_token != "valid_token":
raise HTTPException(status_code=401, detail="Invalid X-Token")
return x_token

app = FastAPI(dependencies=[Depends(verify_token)])

@app.get("/items/")
async def read_items():
return {"items": "This endpoint is protected by a global dependency"}

In this example, verify_token will run for every request to any endpoint in your application.

Use Cases for Global Dependencies

1. Authentication and Authorization

One of the most common use cases for global dependencies is implementing authentication:

python
from fastapi import Depends, FastAPI, Header, HTTPException
from typing import Optional

async def verify_api_key(api_key: str = Header(..., convert_underscores=False)):
if api_key != "your-secret-api-key":
raise HTTPException(status_code=403, detail="Invalid API Key")
return api_key

app = FastAPI(dependencies=[Depends(verify_api_key)])

@app.get("/users/")
async def get_users():
# This endpoint is protected by the global dependency
return {"message": "List of users"}

@app.get("/items/")
async def get_items():
# This endpoint is also protected by the global dependency
return {"message": "List of items"}

2. Request Logging

Global dependencies are excellent for implementing request logging:

python
import time
from fastapi import Depends, FastAPI, Request

async def log_request(request: Request):
start_time = time.time()
# Store the start time in the request state
request.state.start_time = start_time
print(f"Request started: {request.method} {request.url}")

# This will be executed after the request is processed
yield

process_time = time.time() - start_time
print(f"Request completed: {request.method} {request.url} took {process_time:.4f} seconds")

app = FastAPI(dependencies=[Depends(log_request)])

@app.get("/slow-operation/")
async def slow_operation():
# Simulate a slow operation
time.sleep(2)
return {"message": "Operation complete"}

3. Database Session Management

You can use global dependencies to set up and tear down database connections:

python
from fastapi import Depends, FastAPI
from sqlalchemy.orm import Session

# Database setup code omitted for brevity
# Assume we have engine and SessionLocal defined

async def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

app = FastAPI(dependencies=[Depends(get_db)])

@app.get("/users/")
async def get_users(db: Session = Depends(get_db)):
# Use the db session
users = db.query(User).all()
return users

Excluding Routes from Global Dependencies

Sometimes you might want certain routes (like health checks or public endpoints) to be exempt from global dependencies. FastAPI allows you to create separate sub-applications for this purpose:

python
from fastapi import Depends, FastAPI, Header, HTTPException

async def verify_token(x_token: str = Header(...)):
if x_token != "valid_token":
raise HTTPException(status_code=401, detail="Invalid X-Token")
return x_token

app = FastAPI()
secured_app = FastAPI(dependencies=[Depends(verify_token)])

# Mount the secured app under /secured path
app.mount("/secured", secured_app)

# This endpoint is not protected
@app.get("/health/")
async def health_check():
return {"status": "healthy"}

# This endpoint is protected
@secured_app.get("/items/")
async def read_items():
return {"items": "This endpoint is protected"}

Advanced Global Dependencies

Dependency with Sub-Dependencies

Global dependencies can have their own dependencies:

python
from fastapi import Depends, FastAPI, Header, HTTPException

async def get_user_from_token(token: str = Header(...)):
# In a real scenario, you'd verify the token and fetch user info
if token != "valid_token":
raise HTTPException(status_code=401, detail="Invalid token")
return {"user_id": 123, "username": "johndoe"}

async def verify_admin(user: dict = Depends(get_user_from_token)):
if user.get("username") != "admin":
raise HTTPException(status_code=403, detail="Admin privileges required")
return user

app = FastAPI(dependencies=[Depends(verify_admin)])

Adding Multiple Global Dependencies

You can add multiple global dependencies to your application:

python
from fastapi import Depends, FastAPI

async def dep1():
print("Running dependency 1")

async def dep2():
print("Running dependency 2")

async def dep3():
print("Running dependency 3")

app = FastAPI(dependencies=[Depends(dep1), Depends(dep2), Depends(dep3)])

Real-World Example: Complete API with Global Dependencies

Here's a more comprehensive example demonstrating global dependencies in a real-world scenario:

python
from fastapi import Depends, FastAPI, Header, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
import time
from typing import Optional
import jwt
from pydantic import BaseModel

# Models
class User(BaseModel):
id: int
username: str
role: str

# Auth dependency
async def get_current_user(authorization: str = Header(default=None)):
if not authorization:
raise HTTPException(status_code=401, detail="Authorization header missing")

try:
scheme, token = authorization.split()
if scheme.lower() != "bearer":
raise HTTPException(status_code=401, detail="Invalid authentication scheme")

# In production, use proper JWT verification
payload = jwt.decode(token, "secret_key", algorithms=["HS256"])
user = User(
id=payload["user_id"],
username=payload["username"],
role=payload["role"]
)
except Exception as e:
raise HTTPException(status_code=401, detail=f"Invalid token: {str(e)}")

return user

# Logging dependency
async def log_request(request: Request):
request.state.start_time = time.time()
request_id = f"req-{time.time()}"
print(f"[{request_id}] Request started: {request.method} {request.url}")

try:
# Process the request
yield

# Log after request is processed
process_time = time.time() - request.state.start_time
print(f"[{request_id}] Request completed: {process_time:.4f}s")
except Exception as e:
# Log exceptions
process_time = time.time() - request.state.start_time
print(f"[{request_id}] Request failed after {process_time:.4f}s: {str(e)}")
raise

# Create main app without global dependencies
app = FastAPI(title="My API with Global Dependencies")

# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

# Create protected API with global dependencies
secured_app = FastAPI(dependencies=[Depends(get_current_user), Depends(log_request)])

# Mount secured app
app.mount("/api", secured_app)

# Public routes
@app.get("/")
async def root():
return {"message": "Welcome to the API"}

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

# Protected routes
@secured_app.get("/users/me")
async def get_me(current_user: User = Depends(get_current_user)):
return current_user

@secured_app.get("/admin")
async def admin_route(current_user: User = Depends(get_current_user)):
if current_user.role != "admin":
raise HTTPException(status_code=403, detail="Admin privileges required")
return {"message": "Welcome to admin section"}

Best Practices for Global Dependencies

  1. Keep them lightweight: Global dependencies run for every request, so keep them efficient.
  2. Handle errors appropriately: Provide clear error messages when dependencies fail.
  3. Use yield for cleanup: When resources need cleanup (like database sessions), use yield for proper cleanup.
  4. Separate public and secured APIs: Use separate FastAPI instances for public and secured endpoints.
  5. Consider performance: Monitor how global dependencies affect your API's performance.

Summary

Global dependencies in FastAPI provide a clean way to implement functionality that should run for every request to your application. They're particularly useful for:

  • Authentication and authorization
  • Request logging and monitoring
  • Database session management
  • Input validation
  • Cross-cutting concerns

By structuring your global dependencies carefully, you can maintain clean, DRY code while ensuring consistent behavior across your API.

Additional Resources

Exercises

  1. Create a global dependency that tracks and limits the number of requests from a specific IP address.
  2. Implement a global dependency that validates a custom header parameter across all endpoints.
  3. Create an API with both secured and public routes using the mounting technique described in this tutorial.
  4. Implement a global dependency for performance monitoring that logs slow requests (taking over 1 second).
  5. Design a role-based access control system using global dependencies with different permission levels.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)