Skip to main content

FastAPI Request Object

In web applications, understanding and handling incoming HTTP requests is fundamental. FastAPI provides a powerful Request object that gives you access to all the information about the incoming request. This guide will help you understand how to work with the FastAPI Request object effectively.

Introduction to the Request Object

The Request object in FastAPI is an instance of the Starlette Request class that contains all the information about the incoming HTTP request. It allows you to access:

  • HTTP headers
  • Client information (IP address)
  • Query parameters
  • Cookies
  • Request body
  • Form data
  • Request method (GET, POST, etc.)
  • URL details

Understanding how to work with the Request object gives you more control over your API's behavior and enables you to build more sophisticated applications.

Accessing the Request Object

To access the Request object in a FastAPI route, you simply need to add a parameter of type Request to your route function:

python
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/")
async def read_root(request: Request):
return {"message": "Hello World"}

FastAPI will automatically inject the Request object when your endpoint is called.

Common Request Properties

Let's explore some of the most useful properties of the Request object:

1. Accessing HTTP Headers

HTTP headers provide metadata about the request. Here's how to access them:

python
@app.get("/headers")
async def get_headers(request: Request):
user_agent = request.headers.get("user-agent")
content_type = request.headers.get("content-type")

# Access all headers
all_headers = dict(request.headers)

return {
"user-agent": user_agent,
"content-type": content_type,
"all_headers": all_headers
}

When you call this endpoint, you'll see all the headers sent with your request.

2. Getting Client Information

You can access information about the client making the request:

python
@app.get("/client")
async def get_client_info(request: Request):
client_host = request.client.host
client_port = request.client.port

return {
"client_host": client_host,
"client_port": client_port
}

This will return the client's IP address and port number, which can be useful for logging or security measures.

3. URL and Path Parameters

You can access information about the URL:

python
@app.get("/url-info")
async def get_url_info(request: Request):
url = str(request.url)
base_url = str(request.base_url)
path = request.url.path

return {
"full_url": url,
"base_url": base_url,
"path": path
}

This returns details about the current URL being accessed.

4. HTTP Method

Get the HTTP method used for the request:

python
@app.get("/method")
@app.post("/method")
async def get_request_method(request: Request):
return {"method": request.method}

This will return "GET" or "POST" depending on how you access the endpoint.

Working with Request Body Data

One of the most powerful features of the Request object is the ability to access the raw request body. This is particularly useful when you need more control over the parsing process or when dealing with custom content types.

Reading the Raw Request Body

python
@app.post("/raw-body")
async def get_raw_body(request: Request):
body = await request.body()
body_text = body.decode("utf-8")

return {
"body_bytes": len(body),
"body_text": body_text
}

This will read and return the raw body bytes and the decoded text.

Reading JSON Data from the Request

While FastAPI automatically parses JSON for you when using Pydantic models, you can also manually parse JSON from the request body:

python
@app.post("/manual-json")
async def get_manual_json(request: Request):
json_data = await request.json()

return {
"received_data": json_data,
"message": "Manually parsed JSON data"
}

When you send a JSON payload to this endpoint, it will parse and return it.

Form Data and File Uploads

You can also access form data and file uploads:

python
@app.post("/form-data")
async def get_form_data(request: Request):
form_data = await request.form()
form_dict = {}

for key, value in form_data.items():
if hasattr(value, "filename"): # This is a file upload
form_dict[key] = {
"filename": value.filename,
"content_type": value.content_type,
"size_in_bytes": len(await value.read())
}
else: # This is a regular form field
form_dict[key] = value

return {
"form_data": form_dict
}

This endpoint will handle both regular form fields and file uploads.

Cookies and State

You can access cookies from the request:

python
@app.get("/cookies")
async def get_cookies(request: Request):
cookies = request.cookies
return {"cookies": cookies}

FastAPI also allows you to store request-specific state:

python
@app.middleware("http")
async def add_request_info(request: Request, call_next):
# Store information in request state
request.state.started_at = time.time()
request.state.client_ip = request.client.host

response = await call_next(request)

# Use the state information
process_time = time.time() - request.state.started_at
response.headers["X-Process-Time"] = str(process_time)

return response

@app.get("/state")
async def get_state(request: Request):
return {
"started_at": request.state.started_at,
"client_ip": request.state.client_ip
}

This middleware adds custom state to each request, which you can later access in your route handlers.

Real-world Example: Request Logger

Let's implement a practical example: a request logger that captures details about each request:

python
import time
from fastapi import FastAPI, Request
import logging

# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("api_requests.log"),
logging.StreamHandler()
]
)

logger = logging.getLogger("api")

app = FastAPI()

@app.middleware("http")
async def log_request(request: Request, call_next):
start_time = time.time()

# Gather request information
method = request.method
url = str(request.url)
client = request.client.host if request.client else "unknown"
user_agent = request.headers.get("user-agent", "unknown")

# Log request start
logger.info(f"Request started: {method} {url} from {client} using {user_agent}")

# Process the request
response = await call_next(request)

# Calculate processing time
process_time = time.time() - start_time

# Log request completion
logger.info(f"Request completed: {method} {url} - Status: {response.status_code} - Time: {process_time:.4f}s")

# Add processing time header to response
response.headers["X-Process-Time"] = str(process_time)

return response

@app.get("/")
async def root(request: Request):
return {"message": "Hello World"}

@app.get("/items/{item_id}")
async def read_item(request: Request, item_id: int):
return {"item_id": item_id, "client": request.client.host}

@app.post("/submit")
async def submit_data(request: Request):
json_data = await request.json()
return {"received": json_data}

This example demonstrates a real-world application of the Request object:

  1. Captures information about each request including method, URL, client IP, and user agent
  2. Logs the start and completion of each request
  3. Measures and logs the processing time
  4. Adds a custom header with the processing time to the response

Summary

The FastAPI Request object provides a powerful interface to access all aspects of incoming HTTP requests:

  • HTTP headers and client information
  • URL and path details
  • Request body in various formats (raw, JSON, form data)
  • Cookies and custom state storage
  • HTTP method and protocol information

Understanding how to work with the Request object allows you to build more sophisticated web applications and APIs with FastAPI, giving you fine-grained control over request handling.

Additional Resources

Exercises

  1. Create an endpoint that logs all headers sent in a request and returns them sorted alphabetically.
  2. Build a route that accepts file uploads and returns information about the files (name, size, type).
  3. Implement a middleware that tracks and limits the number of requests from a specific IP address.
  4. Create an endpoint that parses both JSON and form data, handling either format gracefully.
  5. Build a simple API rate limiter using the Request object to identify clients.


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