Request Handling¶
This guide covers how Django-Bolt processes requests and how to access request data in your handlers.
The request object¶
Access the full request using a request parameter:
@api.get("/info")
async def request_info(request):
return {
"method": request.get("method"),
"path": request.get("path"),
}
Request properties¶
The request dict contains:
| Property | Type | Description |
|---|---|---|
method |
str |
HTTP method (GET, POST, etc.) |
path |
str |
Request path |
query |
dict |
Query parameters |
params |
dict |
Path parameters |
headers |
dict |
Request headers |
body |
bytes |
Raw request body |
context |
dict |
Authentication context |
Type-safe request¶
For better IDE support, use the Request type:
from django_bolt import Request
@api.get("/profile", auth=[JWTAuthentication()], guards=[IsAuthenticated()])
async def profile(request: Request):
# IDE knows about .user, .context, .get(), etc.
return {"user_id": request.user.id}
The Request type provides:
request.user- Authenticated user (lazy loaded)request.context- Authentication context dictrequest.get(key, default)- Get request propertyrequest[key]- Access request property
Path parameters¶
Extract path parameters using curly braces in the route and matching function arguments:
@api.get("/users/{user_id}/posts/{post_id}")
async def get_post(user_id: int, post_id: int):
return {"user_id": user_id, "post_id": post_id}
Type conversion happens automatically:
int- Converts to integerfloat- Converts to floatstr- Keeps as string (default)
Invalid conversions return a 422 Unprocessable Entity.
Query parameters¶
Parameters without path placeholders become query parameters:
@api.get("/search")
async def search(
q: str, # Required
page: int = 1, # Optional with default
limit: int = 20, # Optional with default
sort: str | None = None # Optional, None if not provided
):
return {"q": q, "page": page, "limit": limit, "sort": sort}
Request body¶
JSON body¶
Use msgspec.Struct for validated JSON bodies:
import msgspec
class CreateUser(msgspec.Struct):
username: str
email: str
age: int | None = None
@api.post("/users")
async def create_user(user: CreateUser):
return {"username": user.username}
Raw body access¶
Access the raw body bytes:
@api.post("/raw")
async def raw_body(request):
body = request.get("body", b"")
return {"size": len(body)}
Headers¶
Using Annotated¶
Extract specific headers:
from typing import Annotated
from django_bolt.param_functions import Header
@api.get("/auth")
async def check_auth(
authorization: Annotated[str, Header(alias="Authorization")]
):
return {"auth": authorization}
Optional headers¶
@api.get("/optional-header")
async def optional_header(
custom: Annotated[str | None, Header(alias="X-Custom")] = None
):
return {"custom": custom}
All headers¶
Access all headers from the request:
@api.get("/headers")
async def all_headers(request):
headers = request.get("headers", {})
return {"headers": dict(headers)}
Cookies¶
Extract cookie values:
from typing import Annotated
from django_bolt.param_functions import Cookie
@api.get("/session")
async def get_session(
session_id: Annotated[str, Cookie(alias="sessionid")]
):
return {"session_id": session_id}
Form data¶
URL-encoded forms¶
from typing import Annotated
from django_bolt.param_functions import Form
@api.post("/login")
async def login(
username: Annotated[str, Form()],
password: Annotated[str, Form()]
):
return {"username": username}
Multipart forms¶
@api.post("/profile")
async def update_profile(
name: Annotated[str, Form()],
bio: Annotated[str, Form()] = ""
):
return {"name": name, "bio": bio}
File uploads¶
from typing import Annotated
from django_bolt.param_functions import File
@api.post("/upload")
async def upload(
files: Annotated[list[dict], File(alias="file")]
):
for f in files:
print(f"Received: {f.get('filename')} ({f.get('size')} bytes)")
return {"uploaded": len(files)}
Each file dict contains:
filename- Original filenamecontent_type- MIME typesize- Size in bytescontent- File bytes
Mixed form and files¶
@api.post("/submit")
async def submit(
title: Annotated[str, Form()],
description: Annotated[str, Form()],
attachments: Annotated[list[dict], File(alias="file")] = []
):
return {
"title": title,
"attachments": len(attachments)
}
Dependency injection¶
Use Depends for reusable parameter extractors:
from django_bolt import Depends
async def get_pagination(page: int = 1, limit: int = 20):
return {"page": page, "limit": limit, "offset": (page - 1) * limit}
@api.get("/items")
async def list_items(pagination=Depends(get_pagination)):
return {"pagination": pagination}
Dependencies can be chained and cached. See Dependency Injection for more details.
Validation errors¶
When request validation fails, Django-Bolt returns a 422 Unprocessable Entity with details: