pypi-fastapi

Description
FastAPI framework, high performance, easy to learn, fast to code, ready for production
Author
tessl
Last updated

How to use

npx @tessl/cli registry install tessl/pypi-fastapi@0.116.0

advanced-responses.md docs/

1
# Advanced Response Types
2
3
FastAPI provides a comprehensive set of response classes for different content types and use cases, including high-performance JSON responses, HTML responses, file serving, streaming, and redirects. These response types enable efficient content delivery optimized for specific scenarios and client requirements.
4
5
## Capabilities
6
7
### High-Performance JSON Responses
8
9
Ultra-fast JSON response classes using optimized JSON libraries for maximum performance.
10
11
```python { .api }
12
class UJSONResponse(Response):
13
def __init__(
14
self,
15
content: Any = None,
16
status_code: int = 200,
17
headers: dict = None,
18
media_type: str = "application/json",
19
background: BackgroundTask = None,
20
) -> None:
21
"""
22
JSON response using ujson for high performance.
23
24
Parameters:
25
- content: Data to serialize as JSON
26
- status_code: HTTP status code
27
- headers: Additional HTTP headers
28
- media_type: Content type header
29
- background: Background task to run after response
30
"""
31
32
class ORJSONResponse(Response):
33
def __init__(
34
self,
35
content: Any = None,
36
status_code: int = 200,
37
headers: dict = None,
38
media_type: str = "application/json",
39
background: BackgroundTask = None,
40
) -> None:
41
"""
42
JSON response using orjson for maximum performance.
43
44
Parameters:
45
- content: Data to serialize as JSON
46
- status_code: HTTP status code
47
- headers: Additional HTTP headers
48
- media_type: Content type header
49
- background: Background task to run after response
50
"""
51
```
52
53
### HTML and Plain Text Responses
54
55
Response classes for serving HTML content and plain text.
56
57
```python { .api }
58
class HTMLResponse(Response):
59
def __init__(
60
self,
61
content: str = "",
62
status_code: int = 200,
63
headers: dict = None,
64
media_type: str = "text/html",
65
background: BackgroundTask = None,
66
) -> None:
67
"""
68
HTML response for serving HTML content.
69
70
Parameters:
71
- content: HTML content string
72
- status_code: HTTP status code
73
- headers: Additional HTTP headers
74
- media_type: Content type header
75
- background: Background task to run after response
76
"""
77
78
class PlainTextResponse(Response):
79
def __init__(
80
self,
81
content: str = "",
82
status_code: int = 200,
83
headers: dict = None,
84
media_type: str = "text/plain",
85
background: BackgroundTask = None,
86
) -> None:
87
"""
88
Plain text response.
89
90
Parameters:
91
- content: Plain text content string
92
- status_code: HTTP status code
93
- headers: Additional HTTP headers
94
- media_type: Content type header
95
- background: Background task to run after response
96
"""
97
```
98
99
### Redirect Responses
100
101
Response class for HTTP redirects with configurable status codes.
102
103
```python { .api }
104
class RedirectResponse(Response):
105
def __init__(
106
self,
107
url: str,
108
status_code: int = 307,
109
headers: dict = None,
110
background: BackgroundTask = None,
111
) -> None:
112
"""
113
HTTP redirect response.
114
115
Parameters:
116
- url: Target URL for redirect
117
- status_code: HTTP redirect status code (301, 302, 307, 308)
118
- headers: Additional HTTP headers
119
- background: Background task to run after response
120
"""
121
```
122
123
### File and Streaming Responses
124
125
Response classes for serving files and streaming large content.
126
127
```python { .api }
128
class FileResponse(Response):
129
def __init__(
130
self,
131
path: str,
132
status_code: int = 200,
133
headers: dict = None,
134
media_type: str = None,
135
filename: str = None,
136
background: BackgroundTask = None,
137
) -> None:
138
"""
139
File download response.
140
141
Parameters:
142
- path: File system path to the file
143
- status_code: HTTP status code
144
- headers: Additional HTTP headers
145
- media_type: Content type (auto-detected if None)
146
- filename: Download filename (Content-Disposition header)
147
- background: Background task to run after response
148
"""
149
150
class StreamingResponse(Response):
151
def __init__(
152
self,
153
content: Iterator[Any],
154
status_code: int = 200,
155
headers: dict = None,
156
media_type: str = None,
157
background: BackgroundTask = None,
158
) -> None:
159
"""
160
Streaming response for large content.
161
162
Parameters:
163
- content: Iterator yielding content chunks
164
- status_code: HTTP status code
165
- headers: Additional HTTP headers
166
- media_type: Content type header
167
- background: Background task to run after response
168
"""
169
```
170
171
## Usage Examples
172
173
### High-Performance JSON Responses
174
175
```python
176
from fastapi import FastAPI
177
from fastapi.responses import UJSONResponse, ORJSONResponse
178
import time
179
180
app = FastAPI()
181
182
# Large dataset for performance comparison
183
large_data = {
184
"users": [
185
{"id": i, "name": f"User {i}", "score": i * 1.5}
186
for i in range(10000)
187
],
188
"timestamp": time.time(),
189
"metadata": {"total": 10000, "version": "1.0"}
190
}
191
192
@app.get("/data/ujson", response_class=UJSONResponse)
193
def get_data_ujson():
194
"""Return large dataset using ujson for faster serialization."""
195
return large_data
196
197
@app.get("/data/orjson", response_class=ORJSONResponse)
198
def get_data_orjson():
199
"""Return large dataset using orjson for maximum performance."""
200
return large_data
201
202
# Set as default response class for entire app
203
app_with_orjson = FastAPI(default_response_class=ORJSONResponse)
204
205
@app_with_orjson.get("/fast")
206
def fast_endpoint():
207
return {"message": "This uses ORJSONResponse by default"}
208
```
209
210
### HTML Responses
211
212
```python
213
from fastapi import FastAPI, Request
214
from fastapi.responses import HTMLResponse
215
216
app = FastAPI()
217
218
@app.get("/", response_class=HTMLResponse)
219
def home():
220
html_content = """
221
<!DOCTYPE html>
222
<html>
223
<head>
224
<title>FastAPI HTML Response</title>
225
<style>
226
body { font-family: Arial, sans-serif; margin: 40px; }
227
.header { color: #2c3e50; }
228
</style>
229
</head>
230
<body>
231
<h1 class="header">Welcome to FastAPI</h1>
232
<p>This is a direct HTML response.</p>
233
<ul>
234
<li><a href="/api/users">API Users</a></li>
235
<li><a href="/api/docs">API Documentation</a></li>
236
</ul>
237
</body>
238
</html>
239
"""
240
return HTMLResponse(content=html_content, status_code=200)
241
242
@app.get("/dynamic/{name}", response_class=HTMLResponse)
243
def dynamic_page(name: str):
244
html_content = f"""
245
<!DOCTYPE html>
246
<html>
247
<head>
248
<title>Hello {name}</title>
249
</head>
250
<body>
251
<h1>Hello, {name}!</h1>
252
<p>This page was generated dynamically.</p>
253
<a href="/">Back to Home</a>
254
</body>
255
</html>
256
"""
257
return HTMLResponse(content=html_content)
258
259
@app.get("/error-page", response_class=HTMLResponse)
260
def error_page():
261
html_content = """
262
<html>
263
<body>
264
<h1>Something went wrong</h1>
265
<p>Please try again later.</p>
266
</body>
267
</html>
268
"""
269
return HTMLResponse(content=html_content, status_code=500)
270
```
271
272
### Redirect Responses
273
274
```python
275
from fastapi import FastAPI, Form
276
from fastapi.responses import RedirectResponse
277
278
app = FastAPI()
279
280
@app.get("/old-url")
281
def old_endpoint():
282
# Permanent redirect (301)
283
return RedirectResponse(url="/new-url", status_code=301)
284
285
@app.get("/new-url")
286
def new_endpoint():
287
return {"message": "This is the new endpoint"}
288
289
@app.post("/login")
290
def login(username: str = Form(...), password: str = Form(...)):
291
# Simulate authentication
292
if username == "admin" and password == "secret":
293
# Temporary redirect after successful login (307)
294
return RedirectResponse(url="/dashboard", status_code=307)
295
else:
296
# Redirect back to login with error
297
return RedirectResponse(url="/login?error=invalid", status_code=303)
298
299
@app.get("/dashboard")
300
def dashboard():
301
return {"message": "Welcome to the dashboard"}
302
303
@app.get("/external-redirect")
304
def external_redirect():
305
# Redirect to external URL
306
return RedirectResponse(url="https://fastapi.tiangolo.com/")
307
308
# Conditional redirects
309
@app.get("/redirect/{target}")
310
def conditional_redirect(target: str):
311
redirect_map = {
312
"docs": "/docs",
313
"redoc": "/redoc",
314
"github": "https://github.com/tiangolo/fastapi",
315
"home": "/"
316
}
317
318
if target in redirect_map:
319
return RedirectResponse(url=redirect_map[target])
320
else:
321
return RedirectResponse(url="/404")
322
```
323
324
### File Responses
325
326
```python
327
from fastapi import FastAPI, HTTPException
328
from fastapi.responses import FileResponse
329
import os
330
from pathlib import Path
331
332
app = FastAPI()
333
334
@app.get("/download/{filename}")
335
def download_file(filename: str):
336
file_path = Path("files") / filename
337
338
if not file_path.exists():
339
raise HTTPException(status_code=404, detail="File not found")
340
341
return FileResponse(
342
path=str(file_path),
343
filename=filename,
344
media_type='application/octet-stream'
345
)
346
347
@app.get("/image/{filename}")
348
def serve_image(filename: str):
349
file_path = Path("images") / filename
350
351
if not file_path.exists():
352
raise HTTPException(status_code=404, detail="Image not found")
353
354
# Auto-detect media type based on file extension
355
return FileResponse(path=str(file_path))
356
357
@app.get("/report/pdf")
358
def download_report():
359
return FileResponse(
360
path="reports/monthly_report.pdf",
361
filename="monthly_report.pdf",
362
media_type="application/pdf"
363
)
364
365
@app.get("/export/csv")
366
def export_data():
367
# Assume CSV file is generated elsewhere
368
return FileResponse(
369
path="exports/data.csv",
370
filename="exported_data.csv",
371
media_type="text/csv",
372
headers={"Custom-Header": "Export-Data"}
373
)
374
```
375
376
### Streaming Responses
377
378
```python
379
from fastapi import FastAPI
380
from fastapi.responses import StreamingResponse
381
import json
382
import time
383
from typing import Iterator
384
385
app = FastAPI()
386
387
def generate_large_csv() -> Iterator[str]:
388
"""Generate large CSV data as iterator."""
389
yield "id,name,email,created_at\n"
390
for i in range(100000):
391
yield f"{i},User{i},user{i}@example.com,2024-01-{(i % 30) + 1:02d}\n"
392
393
@app.get("/export/large-csv")
394
def export_large_csv():
395
return StreamingResponse(
396
generate_large_csv(),
397
media_type="text/csv",
398
headers={"Content-Disposition": "attachment; filename=large_data.csv"}
399
)
400
401
def generate_json_stream() -> Iterator[bytes]:
402
"""Generate streaming JSON response."""
403
yield b'{"data": ['
404
for i in range(1000):
405
if i > 0:
406
yield b','
407
data = {"id": i, "value": f"item_{i}"}
408
yield json.dumps(data).encode("utf-8")
409
yield b']}'
410
411
@app.get("/stream/json")
412
def stream_json():
413
return StreamingResponse(
414
generate_json_stream(),
415
media_type="application/json"
416
)
417
418
def generate_server_sent_events() -> Iterator[str]:
419
"""Generate Server-Sent Events stream."""
420
for i in range(10):
421
yield f"data: Event {i} at {time.time()}\n\n"
422
time.sleep(1)
423
424
@app.get("/events")
425
def server_sent_events():
426
return StreamingResponse(
427
generate_server_sent_events(),
428
media_type="text/plain",
429
headers={"Cache-Control": "no-cache", "Connection": "keep-alive"}
430
)
431
432
async def generate_async_stream() -> Iterator[bytes]:
433
"""Generate async streaming response."""
434
for chunk in range(100):
435
# Simulate async processing
436
await asyncio.sleep(0.01)
437
yield f"Chunk {chunk}\n".encode("utf-8")
438
439
@app.get("/stream/async")
440
async def async_stream():
441
return StreamingResponse(
442
generate_async_stream(),
443
media_type="text/plain"
444
)
445
```
446
447
### Response Headers and Background Tasks
448
449
```python
450
from fastapi import FastAPI, BackgroundTasks
451
from fastapi.responses import JSONResponse, FileResponse
452
import logging
453
454
app = FastAPI()
455
456
def log_download(filename: str, user_ip: str):
457
"""Background task to log file downloads."""
458
logging.info(f"File {filename} downloaded by {user_ip}")
459
460
@app.get("/secure-download/{filename}")
461
def secure_download(filename: str, background_tasks: BackgroundTasks, request: Request):
462
file_path = f"secure_files/{filename}"
463
464
# Add logging as background task
465
background_tasks.add_task(log_download, filename, request.client.host)
466
467
return FileResponse(
468
path=file_path,
469
filename=filename,
470
headers={
471
"X-Custom-Header": "Secure-Download",
472
"Cache-Control": "no-cache"
473
}
474
)
475
476
@app.get("/api/data-with-headers")
477
def data_with_custom_headers():
478
return JSONResponse(
479
content={"data": "response"},
480
headers={
481
"X-API-Version": "1.0",
482
"X-Response-Time": str(time.time()),
483
"Access-Control-Allow-Origin": "*"
484
}
485
)
486
```
487
488
## Types
489
490
```python { .api }
491
from typing import Any, Dict, Iterator, Optional, Union
492
from starlette.responses import Response
493
from starlette.background import BackgroundTask
494
495
# Response content types
496
ResponseContent = Union[str, bytes, Iterator[Any]]
497
498
# Headers type
499
ResponseHeaders = Optional[Dict[str, str]]
500
501
# Background task type
502
BackgroundTaskType = Optional[BackgroundTask]
503
504
# HTTP status codes for redirects
505
RedirectStatusCode = Union[301, 302, 303, 307, 308]
506
```