Header and Cookie Parameters
When you need to access metadata sent by a client that isn't part of the URL path or the query string, you use Header and Cookie parameters. These allow you to capture information like authentication tokens, browser identification, or session identifiers directly into your path operation functions.
Header Parameters
To extract a value from the request headers, declare a parameter in your function using the Header class from fastapi.params.
Most HTTP headers are written with hyphens (e.g., User-Agent), but hyphens are invalid characters for Python variable names. By default, FastAPI automatically converts underscores in your parameter names to hyphens to match standard HTTP headers.
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/items/")
async def read_items(user_agent: str | None = Header(default=None)):
return {"User-Agent": user_agent}
In this example from docs_src/header_params/tutorial001_py310.py, the parameter user_agent will receive the value of the User-Agent header.
How Header Conversion Works
The Header class inherits from Param and includes a specific attribute convert_underscores. In fastapi/params.py, the constructor defaults this to True:
class Header(Param):
def __init__(
self,
# ...
convert_underscores: bool = True,
# ...
):
self.convert_underscores = convert_underscores
super().__init__(...)
If you are working with a non-standard system that requires literal underscores in headers (like strange_header), you must explicitly disable this conversion by passing convert_underscores=False.
@app.get("/items/")
async def read_items(
strange_header: str | None = Header(default=None, convert_underscores=False),
):
return {"strange_header": strange_header}
Note that many web servers and proxies (like Nginx) may strip headers containing underscores by default for security reasons, so use this option with caution.
Cookie Parameters
To access cookies sent by the browser, use the Cookie class. It works identically to Header and Query but looks for the value in the Cookie header of the request.
from fastapi import Cookie, FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(ads_id: str | None = Cookie(default=None)):
return {"ads_id": ads_id}
Internally, Cookie is a subclass of Param that sets its in_ attribute to ParamTypes.cookie. This tells FastAPI's dependency resolver to look in the cookie jar rather than the query string or headers.
Handling Multiple Values
Sometimes a client might send the same header multiple times with different values. To capture all of them in a list, use a list type hint for your parameter.
@app.get("/items/")
async def read_items(x_token: list[str] | None = Header(default=None)):
return {"X-Token values": x_token}
If the request contains multiple X-Token headers, FastAPI will collect them into the x_token list. This is common for headers like Set-Cookie or custom tracking tokens.
Grouping Parameters with Pydantic Models
If you have a large set of related headers or cookies, you can group them into a Pydantic model. This keeps your function signature clean and allows you to reuse the same set of metadata requirements across different endpoints.
Define your model and then use it as the type hint for a parameter assigned to Header() or Cookie().
from fastapi import FastAPI, Header
from pydantic import BaseModel
app = FastAPI()
class CommonHeaders(BaseModel):
host: str
save_data: bool
if_modified_since: str | None = None
x_tag: list[str] = []
@app.get("/items/")
async def read_items(headers: CommonHeaders = Header()):
return headers
FastAPI will extract each field of the CommonHeaders model from the request headers. If a client sends extra headers that are not defined in your model, they are ignored by default. To be strict and reject requests with extra headers, you can configure the model with model_config = {"extra": "forbid"}.
Validation and Metadata
Because Header and Cookie both inherit from Param (which in turn inherits from Pydantic's FieldInfo), they support all standard validation and documentation attributes.
You can enforce constraints like min_length, max_length, or use a pattern (which replaces the deprecated regex parameter) to validate the format of a header or cookie:
@app.get("/items/")
async def read_items(
x_token: str = Header(pattern="^fixedquery$", description="A special security token")
):
return {"token": x_token}
These constraints are automatically included in the generated OpenAPI schema, and FastAPI will return a 422 Unprocessable Entity error if the client sends a value that doesn't match your requirements.