Understanding Dependencies in FastAPI
Understanding Dependencies in FastAPI
FastAPI
Jun 7, 2025 • 5 min read
Tags: Python, FastAPI, Dependency
You just say, “Hey, I need X” with Depends(X), and FastAPI will make sure X is ready
and available when your route runs.
Let’s say that you have a database of users, and you want to protect your endpoints
from unauthorized users. Below is the sample code.
To make things simple, we will use a Python dict to store the users.
app = FastAPI()
USERS = [
{
"id": 1,
"name": "John Doe",
"role": "admin",
"access_token": "token111"
},
{
"id": 2,
"name": "Jane Doe",
"role": "user",
"access_token": "token222"
}
]
nashruddinamin.com
Web Development and AI - Python, React, Rust. 1
@app.get('/protected1')
async def protected1():
return {"message": "You are accessing our protected 1"}
@app.get('/protected2')
async def protected2():
return {"message": "You are accessing our protected 2"}
We want the users to pass their access token when making the HTTP requests to our
endpoints. This access token will be checked against the database, and only users
with valid access token are allowed to access the endpoint.
To avoid repeating the same token validation logic in every endpoint, we can use
FastAPI’s dependency injection system.
nashruddinamin.com
Web Development and AI - Python, React, Rust. 2
...
@app.get('/protected1')
async def protected1(user: Annotated[dict, Depends(get_current_user)]):
return {"message": f"Hello, {user['name']}! You are on protected 1"}
@app.get('/protected2')
async def protected2(user: Annotated[dict, Depends(get_current_user)]):
return {"message": f"Hello, {user['name']}! You are accessing our
protected 2"}
Boom! Now both endpoints are protected. FastAPI will run the get_current_user
function before hitting our endpoint, and if it passes, the user object is injected into the
endpoint.
If user John Doe want to access the protected endpoints, he needs to pass his access
token when making the requests:
Lets say we have another endpoint, /admin-only, that requires not only user with
valid access token, but they should also have the “admin” role.
...
nashruddinamin.com
Web Development and AI - Python, React, Rust. 3
@app.get('/admin-only')
async def admin_only(user: Annotated[dict, Depends(has_role('admin'))]):
return {"message": f"Hello, {user['name']! You are accessing our
admin-only endpoint"}
This chain continues until all dependencies are resolved, and finally, the endpoint
function runs with the validated user object.
The cool part is — you can stack or nest as many dependencies as you like, keeping
your endpoint functions clean and focused only on the business logic.
Class-based dependencies
You are not limited to use function-based dependencies only. You can also use
class-based dependencies for your route functions.
class CurrentUser(object):
def __call__(self, access_token: str = Header(...)):
for user in USERS:
if user["access_token"] == access_token:
return user
raise HTTPException(
status_code=401,
detail="Invalid or missing token"
)
class RoleChecker(object):
def __init__(self, required_role: str):
self.required_role = required_role
nashruddinamin.com
Web Development and AI - Python, React, Rust. 4
@app.get('/protected1')
async def protected1(user: Annotated[dict, Depends(CurrentUser())]):
...
@app.get('/protected2')
async def protected2(user: Annotated[dict, Depends(CurrentUser())]):
...
@app.get('/admin-only')
async def admin_only(user: Annotated[dict, Depends(RoleChecker('admin'))]):
...
Just like before, the /protected1 and /protected2 endpoints only require a valid
token, while /admin-only checks both the token and that the user has the “admin”
role.
app = FastAPI()
USERS = [
{
"id": 1,
"name": "John Doe",
"role": "admin",
"access_token": "token111"
},
{
"id": 2,
"name": "Jane Doe",
"role": "user",
"access_token": "token222"
}
]
nashruddinamin.com
Web Development and AI - Python, React, Rust. 5
for user in USERS:
if user["access_token"] == access_token:
return user
raise HTTPException(status_code=401, detail="Invalid or missing token")
class CurrentUser(object):
"""
Class-based version of the `get_current_user` dependency
"""
def __call__(self, access_token: str = Header(...)):
for user in USERS:
if user["access_token"] == access_token:
return user
raise HTTPException(status_code=401, detail="Invalid or missing
token")
class RoleChecker(object):
"""
Class-based version of the `has_role` dependency
"""
def __init__(self, required_role: str):
self.required_role = required_role
@app.get('/protected1')
async def protected1(user: Annotated[dict, Depends(get_current_user)]):
return {"message": f"Hello, {user['name']}! You are accessing our
protected 1"}
@app.get('/protected2')
async def protected2(user: Annotated[dict, Depends(get_current_user)]):
return {"message": f"Hello, {user['name']}! You are accessing our
protected 2"}
@app.get('/admin-only')
nashruddinamin.com
Web Development and AI - Python, React, Rust. 6
async def admin_only(user: Annotated[dict, Depends(has_role('admin'))]):
return {"message": f"Hello, {user['name']}! You are accessing our admin
endpoint"}
nashruddinamin.com
Web Development and AI - Python, React, Rust. 7