FastAPI Response Object
When building APIs with FastAPI, you often need fine-grained control over the HTTP responses your application sends. The FastAPI Response object gives you this control, allowing you to customize status codes, headers, cookies, and more. This guide will introduce you to the Response object and show you how to leverage its capabilities effectively.
Introduction to Response Objects
In FastAPI, a response object represents the HTTP response that your API will send back to the client. While FastAPI automatically handles responses for you in most cases, there are scenarios where you might want to customize various aspects of the response.
FastAPI provides several response classes through the fastapi.responses
module:
Response
: The base response classJSONResponse
: For returning JSON contentHTMLResponse
: For returning HTML contentPlainTextResponse
: For returning plain textRedirectResponse
: For HTTP redirectsStreamingResponse
: For streaming response contentFileResponse
: For returning file content
Let's explore how to use these response objects to build more powerful APIs.
Basic Usage of Response Objects
Importing Response Classes
First, let's see how to import the response objects:
from fastapi import FastAPI
from fastapi.responses import JSONResponse, HTMLResponse, PlainTextResponse
app = FastAPI()
Returning a Simple Response
Here's a basic example of using the JSONResponse
to return custom JSON data:
@app.get("/custom-json")
def get_custom_json():
content = {"message": "Hello, World!", "status": "success"}
return JSONResponse(content=content, status_code=200)
When you call this endpoint, the output will be:
{
"message": "Hello, World!",
"status": "success"
}
Different Response Types
Let's explore different response types:
HTML Response
@app.get("/html", response_class=HTMLResponse)
def get_html():
html_content = """
<html>
<head>
<title>FastAPI HTML Response</title>
</head>
<body>
<h1>Hello from FastAPI!</h1>
</body>
</html>
"""
return HTMLResponse(content=html_content)
Plain Text Response
@app.get("/text", response_class=PlainTextResponse)
def get_text():
return PlainTextResponse("Hello, this is a plain text response")
Customizing Response Headers
Headers are an essential part of HTTP responses. FastAPI allows you to easily set custom headers:
from fastapi import FastAPI, Response
app = FastAPI()
@app.get("/custom-header")
def get_with_headers(response: Response):
response.headers["X-Custom-Header"] = "custom header value"
response.headers["Cache-Control"] = "max-age=3600"
return {"message": "Custom headers set"}
You can also set headers directly when creating a response object:
@app.get("/direct-headers")
def get_with_direct_headers():
content = {"message": "Response with custom headers"}
headers = {
"X-Custom-Header": "value",
"X-Another-Header": "another value"
}
return JSONResponse(content=content, headers=headers)
Setting Cookies with Response Object
Cookies are easily managed using the Response object:
@app.get("/set-cookie")
def set_cookie(response: Response):
response.set_cookie(
key="session",
value="session_value",
max_age=3600,
httponly=True,
secure=True,
samesite="lax"
)
return {"message": "Cookie set"}
Controlling Status Codes
Status codes are crucial for communicating the result of an HTTP request:
@app.get("/not-found")
def get_not_found():
return JSONResponse(
status_code=404,
content={"message": "Item not found"}
)
@app.get("/server-error")
def get_server_error():
return JSONResponse(
status_code=500,
content={"message": "Internal server error"}
)
Advanced Response Scenarios
File Downloads with FileResponse
The FileResponse
class makes it easy to return files from your API:
from fastapi.responses import FileResponse
@app.get("/download-file")
def download_file():
file_path = "path/to/your/file.pdf"
return FileResponse(
path=file_path,
filename="downloaded-file.pdf",
media_type="application/pdf"
)
Streaming Responses
For large responses or when you need to stream data, use StreamingResponse
:
from fastapi.responses import StreamingResponse
import io
@app.get("/stream")
def stream_response():
def generate_data():
for i in range(10):
yield f"data: {i}\n\n"
return StreamingResponse(
generate_data(),
media_type="text/event-stream"
)
Redirect Responses
Redirecting users is a common requirement in web applications:
from fastapi.responses import RedirectResponse
@app.get("/redirect")
def redirect_to_docs():
return RedirectResponse(url="/docs")
@app.get("/permanent-redirect")
def permanent_redirect():
# 301 is a permanent redirect
return RedirectResponse(url="/home", status_code=301)
Practical Example: Building an API with Custom Responses
Let's build a more comprehensive example that demonstrates different response types in a simple user management API:
from fastapi import FastAPI, HTTPException, Response, status
from fastapi.responses import JSONResponse, HTMLResponse
from pydantic import BaseModel
from typing import List, Optional
app = FastAPI()
# Model for our user
class User(BaseModel):
id: int
name: str
email: str
# Mock database
users_db = [
User(id=1, name="John Doe", email="[email protected]"),
User(id=2, name="Jane Smith", email="[email protected]")
]
# Get all users
@app.get("/users", response_model=List[User])
def get_users():
return users_db
# Get user by ID with different response formats
@app.get("/users/{user_id}")
def get_user(user_id: int, format: Optional[str] = None):
for user in users_db:
if user.id == user_id:
# Different response formats based on query parameter
if format == "html":
html_content = f"""
<html>
<head>
<title>User {user.id}</title>
</head>
<body>
<h1>{user.name}</h1>
<p>Email: {user.email}</p>
</body>
</html>
"""
return HTMLResponse(content=html_content)
else:
# Default JSON response
return user
# Custom error response when user not found
return JSONResponse(
status_code=404,
content={"message": f"User with id {user_id} not found"}
)
# Create a user with status code
@app.post("/users", status_code=status.HTTP_201_CREATED)
def create_user(user: User, response: Response):
# Check if user already exists
for existing_user in users_db:
if existing_user.id == user.id:
return JSONResponse(
status_code=400,
content={"message": f"User with id {user.id} already exists"}
)
users_db.append(user)
response.headers["Location"] = f"/users/{user.id}"
return user
# Delete a user
@app.delete("/users/{user_id}")
def delete_user(user_id: int):
for index, user in enumerate(users_db):
if user.id == user_id:
users_db.pop(index)
return Response(status_code=204)
raise HTTPException(status_code=404, detail=f"User with id {user_id} not found")
This example demonstrates:
- Different response formats based on query parameters
- Setting status codes for different scenarios
- Custom headers in responses
- Using the built-in HTTPException
- Returning a 204 No Content response
Summary
The FastAPI Response object gives you powerful control over HTTP responses in your API:
- You can choose from various response types like JSON, HTML, plain text, file downloads, and more
- You can set custom headers, cookies, and status codes
- Response objects help you build more sophisticated APIs with fine-grained control over how data is sent to clients
Understanding how to work with response objects is essential for building robust and flexible APIs with FastAPI.
Additional Resources
Exercises
- Create an endpoint that returns different response formats (JSON, HTML, CSV) based on a query parameter.
- Build a file upload and download system using
FileResponse
. - Implement a streaming endpoint that sends progress updates to the client.
- Create a login endpoint that sets secure cookies and returns appropriate status codes for success/failure.
- Build an API endpoint that returns custom headers with information about rate limiting.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)