Skip to main content

FastAPI Request Headers

HTTP headers provide crucial information about requests and responses in web applications. In FastAPI, working with request headers is straightforward yet powerful, giving you access to important metadata sent by clients. This guide will teach you how to access, validate, and utilize headers in your FastAPI applications.

What are HTTP Headers?

HTTP headers are key-value pairs sent with every HTTP request and response. They contain metadata about the request or response such as:

  • Content type and length
  • Authentication credentials
  • Cache directives
  • Client information (like user-agent)
  • Custom application-specific data

Headers provide crucial context for API operations without being part of the main request body.

Accessing Headers in FastAPI

FastAPI provides several ways to access request headers:

Method 1: Using the Header Parameter

The most common approach is using FastAPI's Header class:

python
from fastapi import FastAPI, Header

app = FastAPI()

@app.get("/headers")
async def read_header(user_agent: str = Header(None)):
return {"User-Agent": user_agent}

In this example, FastAPI:

  1. Extracts the User-Agent header from the request
  2. Converts it into the user_agent parameter
  3. Returns it in the response

When you make a request to /headers, you'll receive a JSON response with your browser's user-agent string:

json
{
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36..."
}

Method 2: Accessing the Request Object

You can also access all headers through the Request object:

python
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/all-headers")
async def read_all_headers(request: Request):
return {"headers": dict(request.headers)}

This approach gives you access to all headers at once, returning something like:

json
{
"headers": {
"host": "localhost:8000",
"user-agent": "Mozilla/5.0...",
"accept": "text/html,application/xhtml+xml...",
"accept-encoding": "gzip, deflate",
"accept-language": "en-US,en;q=0.9",
"connection": "keep-alive"
}
}

Header Parameter Naming

HTTP headers are conventionally written with "dash-case" formatting (e.g., Content-Type, User-Agent). However, Python variables can't contain dashes. FastAPI handles this automatically:

python
from fastapi import FastAPI, Header

app = FastAPI()

@app.get("/header-conversion")
async def read_header(
user_agent: str = Header(None),
content_type: str = Header(None),
x_custom_header: str = Header(None)
):
return {
"User-Agent": user_agent,
"Content-Type": content_type,
"X-Custom-Header": x_custom_header
}

FastAPI automatically:

  • Converts user_agent to user-agent
  • Converts content_type to content-type
  • Converts x_custom_header to x-custom-header

If you want to disable this automatic conversion, use the convert_underscores parameter:

python
@app.get("/no-conversion")
async def no_conversion(
strange_header: str = Header(None, convert_underscores=False)
):
# Now FastAPI will look for a header named exactly "strange_header"
return {"strange_header": strange_header}

Required and Default Headers

Like other parameters, you can make headers required or provide default values:

python
from fastapi import FastAPI, Header

app = FastAPI()

# Required header
@app.get("/required-header")
async def required_header(api_key: str = Header(...)):
return {"api_key": api_key}

# Default value if header not provided
@app.get("/default-header")
async def default_header(accept: str = Header("application/json")):
return {"accept": accept}

For the /required-header endpoint, if the api-key header is not provided, FastAPI will return a validation error:

json
{
"detail": [
{
"loc": ["header", "api-key"],
"msg": "field required",
"type": "value_error.missing"
}
]
}

Working with Multiple Header Values

Some HTTP headers can appear multiple times in a request. By default, FastAPI combines these into a single comma-separated string, but you can receive them as a list:

python
from fastapi import FastAPI, Header
from typing import List

app = FastAPI()

@app.get("/multiple-values")
async def multiple_values(
x_token: List[str] = Header(None)
):
return {"X-Token values": x_token}

If a client sends multiple X-Token headers, FastAPI will provide them as a list.

Practical Examples

Example 1: API Key Authentication

A common use for headers is API authentication:

python
from fastapi import FastAPI, Header, HTTPException

app = FastAPI()

API_KEYS = {
"user1": "sk_test_abc123",
"user2": "sk_test_xyz789"
}

@app.get("/protected-resource")
async def protected_resource(api_key: str = Header(...)):
if api_key not in API_KEYS.values():
raise HTTPException(status_code=401, detail="Invalid API Key")

# Find the user associated with this key
for user, key in API_KEYS.items():
if key == api_key:
return {"message": f"Hello, {user}! Access granted."}

Example 2: Content Negotiation

Headers can determine what format a client prefers:

python
from fastapi import FastAPI, Header, HTTPException
from fastapi.responses import JSONResponse, PlainTextResponse, HTMLResponse

app = FastAPI()

data = {
"name": "FastAPI",
"description": "A modern, fast web framework for building APIs with Python"
}

@app.get("/content")
async def content_negotiation(accept: str = Header("application/json")):
if "application/json" in accept:
return JSONResponse(content=data)
elif "text/plain" in accept:
return PlainTextResponse(content=f"{data['name']}: {data['description']}")
elif "text/html" in accept:
html_content = f"""
<!DOCTYPE html>
<html>
<head><title>{data['name']}</title></head>
<body>
<h1>{data['name']}</h1>
<p>{data['description']}</p>
</body>
</html>
"""
return HTMLResponse(content=html_content)
else:
raise HTTPException(status_code=406, detail="Not Acceptable")

Example 3: Conditional Requests

Headers can help with resource caching:

python
import hashlib
from datetime import datetime
from fastapi import FastAPI, Header, Response

app = FastAPI()

content = "This is the resource content"
etag = hashlib.md5(content.encode()).hexdigest()
last_modified = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")

@app.get("/conditional")
async def conditional_request(
response: Response,
if_none_match: str = Header(None),
if_modified_since: str = Header(None)
):
# Add headers to the response
response.headers["ETag"] = etag
response.headers["Last-Modified"] = last_modified

# Check if the client has a fresh copy
if if_none_match == etag:
response.status_code = 304 # Not Modified
return ""

# Return the content
return {"content": content, "etag": etag, "last_modified": last_modified}

Common Headers and Their Uses

Here are some important HTTP headers you might work with:

HeaderDescriptionExample
User-AgentClient identificationMozilla/5.0 (Windows NT 10.0; Win64; x64)...
AuthorizationAuthentication credentialsBearer eyJhbGciOiJIUzI1NiIsInR5cCI...
Content-TypeMedia type of the bodyapplication/json
AcceptAcceptable content typesapplication/json, text/plain, */*
CookieHTTP cookiessession=abc123; user=john
X-*Custom headersX-Request-ID: 123456

Validation and Dependencies

You can apply the same validation rules to headers as you would with other parameters:

python
from fastapi import FastAPI, Header
from pydantic import BaseModel, validator

app = FastAPI()

@app.get("/validate-version")
async def validate_version(api_version: str = Header(...)):
# Custom validation
versions = ["1.0", "1.1", "2.0"]
if api_version not in versions:
return {"error": f"API version must be one of {versions}"}

return {"message": f"Using API version: {api_version}"}

Summary

Headers are a powerful tool in HTTP communication that allow you to send metadata with your requests and responses. In FastAPI:

  • Use the Header class to extract and validate headers
  • FastAPI automatically converts between Python's snake_case and HTTP's dash-case
  • You can make headers required or provide default values
  • Headers can be used for authentication, content negotiation, caching, and more

Understanding how to work with headers gives you access to important client information and allows you to implement advanced API features like authentication, caching, and content negotiation.

Additional Resources

Exercises

  1. Create a FastAPI endpoint that returns the client's browser and operating system based on the User-Agent header.
  2. Implement a basic authentication system using the Authorization header.
  3. Build an endpoint that serves different content types (HTML, JSON, XML) based on the Accept header.
  4. Create a cache system using ETag and If-None-Match headers to avoid sending the same content twice.
  5. Design an API versioning system using custom headers.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)