Dependency injection is a way to provide components with their dependencies instead of having the components create them themselves. In FastAPI, dependencies are functions that are called before the main function of an endpoint. These functions can perform tasks such as authentication, data validation, or database connections.
FastAPI uses Python’s type hints to identify and resolve dependencies. When you define a dependency, you can use the Depends
class from the fastapi
module. FastAPI will call the dependency function and pass the result as an argument to the main function of the endpoint.
from fastapi import FastAPI, Depends
app = FastAPI()
# Define a simple dependency function
def get_db():
# Here you can establish a database connection
# For simplicity, we just return a string
return "Database Connection"
@app.get("/items/")
async def read_items(db = Depends(get_db)):
return {"database": db}
In this example, the get_db
function is a dependency. When a client makes a request to the /items/
endpoint, FastAPI will first call the get_db
function and pass the result as the db
argument to the read_items
function.
Dependencies can also depend on other dependencies. Here is an example:
from fastapi import FastAPI, Depends
app = FastAPI()
def get_db():
return "Database Connection"
def get_user(db = Depends(get_db)):
return f"User retrieved from {db}"
@app.get("/users/")
async def read_users(user = Depends(get_user)):
return {"user": user}
In this example, the get_user
function depends on the get_db
function. FastAPI will first call get_db
, then pass the result to get_user
, and finally pass the result of get_user
to the read_users
function.
You can also use a class as a dependency. The class should have a __call__
method.
from fastapi import FastAPI, Depends
app = FastAPI()
class CommonQueryParams:
def __init__(self, q: str | None = 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()):
return {"q": commons.q, "skip": commons.skip, "limit": commons.limit}
In this example, the CommonQueryParams
class is used as a dependency. FastAPI will create an instance of the class and pass it as the commons
argument to the read_items
function.
One of the most common use cases for dependencies in FastAPI is authentication. Here is an example of a simple authentication dependency:
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import APIKeyHeader
app = FastAPI()
api_key_header = APIKeyHeader(name="X-API-Key")
def get_api_key(api_key: str = Depends(api_key_header)):
if api_key != "mysecretkey":
raise HTTPException(status_code=401, detail="Invalid API Key")
return api_key
@app.get("/protected/")
async def read_protected_data(api_key = Depends(get_api_key)):
return {"message": "This is protected data"}
In this example, the get_api_key
function is an authentication dependency. It checks if the API key in the X-API-Key
header is valid. If not, it raises a 401 Unauthorized
error.
Dependencies can also be used for data validation. For example, you can create a dependency to validate that a query parameter is a positive integer:
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
def validate_positive_integer(num: int):
if num <= 0:
raise HTTPException(status_code=400, detail="Number must be positive")
return num
@app.get("/numbers/")
async def read_numbers(num: int = Depends(validate_positive_integer)):
return {"number": num}
Each dependency should have a single responsibility. For example, an authentication dependency should only handle authentication, and a database connection dependency should only handle database connections. This makes the code more modular and easier to maintain.
FastAPI relies on type hints to resolve dependencies. Make sure to use clear and accurate type hints in your dependency functions and classes. This will not only help FastAPI work correctly but also make your code more readable.
Document what each dependency does, what parameters it takes, and what it returns. This will make it easier for other developers (and yourself in the future) to understand and use your code.
FastAPI’s dependency injection system is a powerful tool that can greatly simplify the development of web applications. It allows you to reuse code, simplify testing, and separate concerns in your application. By understanding the fundamental concepts, usage methods, common practices, and best practices of dependency injection in FastAPI, you can build more robust and maintainable APIs.