Header Parameter Models
Group header parameters into Pydantic models for organized access to multiple headers at once.
🎯 What You'll Learn
- •Group header parameters into Pydantic models
- •Understand hyphen-to-underscore conversion in header models
- •Apply validation to groups of headers
- •Handle optional and required header groups
Header Parameter Models
What You'll Learn
HTTP headers carry metadata with every request -- authentication tokens, content types, language preferences, and more. When your endpoint needs to read several headers, declaring them individually becomes repetitive. FastAPI 0.115+ lets you group headers into a Pydantic model.
By the end of this lesson, you'll understand how to:
- Group header parameters into Pydantic models
- Understand the automatic hyphen-to-underscore conversion
- Apply validation to groups of headers
- Handle optional and required header groups
Headers in HTTP
Every HTTP request includes headers. Some common ones:
GET /info/ HTTP/1.1
Host: example.com
X-Token: secret123
X-Request-ID: req-456
Accept-Language: en-US
Content-Type: application/json
Headers are used for authentication, content negotiation, request tracking, and many other cross-cutting concerns.
Individual Header Parameters
Without header models, you declare each header separately:
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/info/")
def get_info(
x_token: str = Header(),
x_request_id: str | None = Header(default=None),
accept_language: str = Header(default="en"),
):
return {
"token": x_token,
"request_id": x_request_id,
"language": accept_language,
}
This works but gets unwieldy when you need many headers across multiple endpoints.
Header Parameter Models
With FastAPI 0.115+, you can group headers into a Pydantic model:
from fastapi import FastAPI, Header
from pydantic import BaseModel
app = FastAPI()
class CommonHeaders(BaseModel):
x_token: str
x_request_id: str | None = None
accept_language: str = "en"
@app.get("/info/")
def get_info(headers: CommonHeaders = Header()):
return {"headers": headers.model_dump()}
The Header() annotation tells FastAPI to read each model field from the request headers.
Key Concepts
Hyphen-to-Underscore Conversion
HTTP headers traditionally use hyphens (X-Token, Accept-Language), but Python variable names cannot contain hyphens. FastAPI automatically converts between the two:
| HTTP Header | Python Field Name |
|---|---|
X-Token | x_token |
X-Request-ID | x_request_id |
Accept-Language | accept_language |
This conversion happens transparently. You define your model fields with underscores, and FastAPI reads the corresponding hyphenated headers from the request.
Required vs Optional Headers
Fields without a default value are required. If the client does not send the header, FastAPI returns a 422 error:
class CommonHeaders(BaseModel):
x_token: str # required - 422 if missing
x_request_id: str | None = None # optional - None if missing
accept_language: str = "en" # optional - "en" if missing
Validation
You can apply Pydantic validation to header fields:
from pydantic import BaseModel, Field
class CommonHeaders(BaseModel):
x_token: str = Field(min_length=10)
x_request_id: str | None = None
accept_language: str = Field(default="en", pattern=r"^[a-z]{2}(-[A-Z]{2})?$")
This ensures x_token is at least 10 characters and accept_language matches a locale pattern like en or en-US.
Reusability Across Endpoints
The same header model can be shared across multiple endpoints:
@app.get("/info/")
def get_info(headers: CommonHeaders = Header()):
return {"headers": headers.model_dump()}
@app.get("/protected/")
def protected_resource(headers: CommonHeaders = Header()):
return {"message": "Access granted", "user_token": headers.x_token}
Both endpoints require the same set of headers without duplicating the parameter declarations.
Combining with Other Parameter Types
Header models work alongside query parameters, path parameters, and request bodies:
@app.get("/items/{item_id}")
def get_item(
item_id: int,
headers: CommonHeaders = Header(),
):
return {
"item_id": item_id,
"token": headers.x_token,
"language": headers.accept_language,
}
Best Practices
- Mark authentication headers as required -- missing tokens should cause errors, not silent defaults
- Provide defaults for preference headers like
accept_languagesince not all clients set them - Use
Nonefor optional tracking headers like request IDs that may or may not be present - Group related headers -- separate authentication headers from preference headers into different models if needed
- Add validation for security-sensitive headers like tokens to enforce minimum lengths
Common Mistakes
Forgetting the Header() annotation
# Wrong - FastAPI treats this as a JSON body
def get_info(headers: CommonHeaders):
...
# Correct - FastAPI reads from headers
def get_info(headers: CommonHeaders = Header()):
...
Using hyphens in field names
# Wrong - Python syntax error
class CommonHeaders(BaseModel):
x-token: str # invalid!
# Correct - use underscores
class CommonHeaders(BaseModel):
x_token: str # FastAPI reads "x-token" header
What's Next?
You now know how to group headers into Pydantic models. Next, you will learn how to apply the same pattern to HTML form fields using Request Form Models.
💡 Hint
Create a Pydantic model with header fields and annotate the parameter with Header().
Ready to Practice?
Now that you understand the theory, let's put it into practice with hands-on coding!
Start Interactive Lesson