Skip to main content

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 class
  • JSONResponse: For returning JSON content
  • HTMLResponse: For returning HTML content
  • PlainTextResponse: For returning plain text
  • RedirectResponse: For HTTP redirects
  • StreamingResponse: For streaming response content
  • FileResponse: 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:

python
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:

python
@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:

json
{
"message": "Hello, World!",
"status": "success"
}

Different Response Types

Let's explore different response types:

HTML Response

python
@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

python
@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:

python
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:

python
@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:

python
@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:

python
@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:

python
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:

python
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:

python
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:

python
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:

  1. Different response formats based on query parameters
  2. Setting status codes for different scenarios
  3. Custom headers in responses
  4. Using the built-in HTTPException
  5. 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

  1. Create an endpoint that returns different response formats (JSON, HTML, CSV) based on a query parameter.
  2. Build a file upload and download system using FileResponse.
  3. Implement a streaming endpoint that sends progress updates to the client.
  4. Create a login endpoint that sets secure cookies and returns appropriate status codes for success/failure.
  5. 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! :)