Skip to main content

FastAPI Dependency Functions

In this tutorial, you'll learn about dependency functions in FastAPI - one of the framework's most powerful features that helps you build cleaner, more maintainable APIs.

Introduction to Dependency Functions

Dependency functions in FastAPI are regular Python functions that can be "injected" into path operation functions. They allow you to:

  • Reuse code: Write functionality once and use it in multiple endpoints
  • Share logic: Apply common processing steps across different routes
  • Organize your code: Keep your endpoint functions clean and focused
  • Handle cross-cutting concerns: Like authentication, database connections, and parameter validation

Think of dependencies as building blocks that you can combine and reuse throughout your application.

Basic Dependency Function

Let's start with a simple example:

python
from fastapi import Depends, FastAPI

app = FastAPI()

# This is our dependency function
def get_query_parameter(q: str = None):
return q or "No query parameter provided"

@app.get("/items/")
async def read_items(query_result: str = Depends(get_query_parameter)):
return {"query_result": query_result}

In this example:

  1. We define a dependency function get_query_parameter that processes a query parameter
  2. We use Depends(get_query_parameter) to inject this function into our path operation
  3. FastAPI calls the dependency function before the path operation
  4. The return value from the dependency is passed as the query_result parameter

When you visit /items/?q=test, you'll get:

json
{
"query_result": "test"
}

And when you visit /items/, you'll get:

json
{
"query_result": "No query parameter provided"
}

How Dependency Injection Works

When you use Depends(), FastAPI does the following:

  1. It sees that your path operation function needs a parameter that is declared with Depends()
  2. It calls the dependency function (passed to Depends()) with the appropriate parameters
  3. It takes the return value from that function
  4. It assigns that return value to your path operation function parameter

Dependency Function Parameters

Dependency functions can have the same parameter types as path operation functions:

python
from fastapi import Depends, FastAPI, Header, HTTPException

app = FastAPI()

def verify_token(x_token: str = Header()):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
return x_token

def verify_key(x_key: str = Header()):
if x_key != "fake-super-secret-key":
raise HTTPException(status_code=400, detail="X-Key header invalid")
return x_key

@app.get("/items/")
async def read_items(token: str = Depends(verify_token), key: str = Depends(verify_key)):
return {"token": token, "key": key}

In this example, both dependency functions check for specific headers and raise exceptions if they're not valid.

Nested Dependencies

A dependency can itself declare dependencies:

python
from fastapi import Depends, FastAPI

app = FastAPI()

def query_extractor(q: str = None):
return q or "default query"

def query_validator(q_or_default: str = Depends(query_extractor)):
if not q_or_default:
return "No query"
if q_or_default != "default query":
return q_or_default
return "default query (validated)"

@app.get("/items/")
async def read_items(final_query: str = Depends(query_validator)):
return {"query": final_query}

Here:

  1. query_validator depends on query_extractor
  2. When read_items is called, FastAPI first calls query_extractor
  3. Then it passes the result to query_validator
  4. Finally, it passes the result of query_validator to read_items

Classes as Dependencies

You can also use classes as dependencies with the Depends function:

python
from fastapi import Depends, FastAPI

app = FastAPI()

class CommonQueryParams:
def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit

@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
response = {}
if commons.q:
response.update({"q": commons.q})
return {
"response": response,
"skip": commons.skip,
"limit": commons.limit
}

This creates a dependency that:

  1. Receives query parameters q, skip, and limit
  2. Returns an instance of CommonQueryParams
  3. Makes the instance available to the path operation function

Shortcut for Class Dependencies

FastAPI provides a shortcut for class-based dependencies. Instead of writing Depends(CommonQueryParams), you can write:

python
@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends()):
# ...

FastAPI will understand that it needs to use the CommonQueryParams class itself as a dependency.

Dependency in Path Operation Decorators

You can add dependencies to the path operation decorator:

python
from fastapi import Depends, FastAPI, Header, HTTPException

app = FastAPI()

async def verify_token(x_token: str = Header()):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")

@app.get("/items/", dependencies=[Depends(verify_token)])
async def read_items():
return [{"item": "Foo"}, {"item": "Bar"}]

Here, the dependency is executed before the path operation function but its value is not used in the function itself.

Real-World Example: Database Dependencies

One common use case for dependencies is handling database connections:

python
from fastapi import Depends, FastAPI
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session, sessionmaker

# Database setup
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

app = FastAPI()

# Dependency function
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

@app.get("/users/")
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
# Here you would use the db session to query users
return [{"username": "user1"}, {"username": "user2"}]

In this example:

  1. We define a dependency function get_db that creates a database session
  2. The yield statement returns the database session to the path operation function
  3. After the path operation function completes, the code after the yield runs
  4. This ensures the database connection is always closed, even if an exception occurs

Summary

FastAPI dependency functions provide a powerful way to:

  • Reuse code across multiple endpoints
  • Handle common functionality like authentication or database connections
  • Keep your route handlers clean and focused on their specific tasks
  • Build maintainable applications with separation of concerns

By mastering dependency injection, you'll be able to build more modular and maintainable FastAPI applications.

Further Learning

Here are some exercises to strengthen your understanding:

  1. Create a dependency that validates a custom header parameter
  2. Build a dependency chain with at least three levels of nested dependencies
  3. Implement a dependency that simulates rate limiting (returning an error if too many requests are made)
  4. Create a dependency that logs all incoming requests with their path and query parameters

Additional Resources

Happy coding with FastAPI dependencies!



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