title: Dependency Injection
description: Use Depends to inject reusable components into your JustAPI route handlers — a FastAPI-compatible DI system.
keywords: dependency injection, Depends, route handlers, FastAPI alternative, JustAPI, reusable components
Dependency Injection (DI) lets you declare reusable components that are automatically resolved and injected into your route handlers. JustAPI's DI system mirrors FastAPI's, making migration seamless.
Basic Dependency
A dependency is any callable that returns a value:
from justapi import JustAPIApp, Depends
app = JustAPIApp()
def common_params(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
def list_items(request, params: dict = Depends(common_params)):
return {"endpoint": "items", **params}
@app.get("/users/")
def list_users(request, params: dict = Depends(common_params)):
return {"endpoint": "users", **params}
curl "http://127.0.0.1:8000/items/?skip=10&limit=5"
# Output: {"endpoint":"items","q":null,"skip":10,"limit":5}
Authentication Dependency
Dependencies can raise HTTPException to reject requests:
from justapi import JustAPIApp, Depends, HTTPException, Header
app = JustAPIApp()
def verify_token(authorization: str = Header(...)):
if not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Invalid authorization header")
token = authorization.removeprefix("Bearer ")
if token != "secret-token":
raise HTTPException(status_code=401, detail="Invalid token")
return {"user_id": 42, "role": "admin"}
@app.get("/protected")
def protected_route(request, user: dict = Depends(verify_token)):
return {"message": "Access granted", "user": user}
curl http://127.0.0.1:8000/protected
# Output: {"detail":"Invalid authorization header"}
curl http://127.0.0.1:8000/protected \
-H "Authorization: Bearer secret-token"
# Output: {"message":"Access granted","user":{"user_id":42,"role":"admin"}}
Database Session Dependency
def get_db(request):
db = app.db
try:
yield db
finally:
pass # Connection pooling handles cleanup
@app.get("/users")
def list_users(request, db=Depends(get_db)):
return db.query("SELECT * FROM users")
Class-Based Dependencies
class Pagination:
def __init__(self, skip: int = 0, limit: int = 100):
self.skip = skip
self.limit = limit
@app.get("/items/")
def list_items(request, pagination: Pagination = Depends(Pagination)):
return {"skip": pagination.skip, "limit": pagination.limit}
Dependency Scope & Caching
By default, dependencies are called once per request and the result is cached. All route handlers and nested dependencies share the same instance:
def get_db(request):
print("Creating DB session") # Called once per request
return {"connection": "db-1"}
def get_user(request, db=Depends(get_db)):
return {"user": "alice", "db": db}
@app.get("/profile")
def profile(request, user=Depends(get_user), db=Depends(get_db)):
return {"user": user, "db_again": db}
In this example, get_db is called once and its result is reused by get_user and profile.
Dependency with Path(), Query(), Header()
from justapi import Path, Query, Header
def pagination(
skip: int = Query(0, description="Number of items to skip"),
limit: int = Query(10, description="Max items per page"),
):
return {"skip": skip, "limit": limit}
def auth(
user_id: int = Path(..., description="User ID"),
authorization: str = Header(..., description="Bearer token"),
):
if authorization != "Bearer secret":
raise HTTPException(401)
return {"user_id": user_id}
@app.get("/users/{user_id}/items/")
def list_items(
request,
auth_data: dict = Depends(auth),
pagination_data: dict = Depends(pagination),
):
return {**auth_data, **pagination_data}
Nested Dependencies
Dependencies can depend on other dependencies:
def get_config(request):
return {"db_url": "postgres://localhost/mydb"}
def get_db(request, config: dict = Depends(get_config)):
return {"connection": f"Connected to {config['db_url']}"}
@app.get("/status")
def status(request, db: dict = Depends(get_db)):
return {"db_status": db["connection"]}
How It Works Internally
- JustAPI inspects function signatures at registration time
- Parameters with
Depends()are resolved before the handler runs - Dependencies execute in order (innermost first)
- Results are cached to avoid redundant calls
HTTPExceptionraised in a dependency short-circuits the request
Next Steps
- Middleware — Request/response interception
- Error Handling — Custom exception handlers
- Database Integration — Real database dependencies