0
# Request and Response Handling
1
2
Comprehensive request and response objects for handling HTTP communications in Sanic applications. The Request object provides access to all incoming request data, while response functions create properly formatted HTTP responses.
3
4
## Capabilities
5
6
### Request Object
7
8
The Request object contains all information about the incoming HTTP request, including headers, body data, query parameters, and metadata.
9
10
```python { .api }
11
class Request:
12
"""HTTP request object containing request data and metadata."""
13
14
@property
15
def app(self):
16
"""Reference to the Sanic application instance."""
17
18
@property
19
def body(self) -> bytes:
20
"""Raw request body as bytes."""
21
22
@property
23
def content_type(self) -> str:
24
"""Request content type from headers."""
25
26
@property
27
def json(self):
28
"""
29
Request body parsed as JSON.
30
31
Returns:
32
Parsed JSON data or None if not JSON
33
34
Raises:
35
InvalidUsage: If JSON is malformed
36
"""
37
38
@property
39
def form(self) -> dict:
40
"""
41
Form data from request body.
42
43
Returns:
44
Dictionary of form fields
45
"""
46
47
@property
48
def files(self) -> dict:
49
"""
50
Uploaded files from multipart form data.
51
52
Returns:
53
Dictionary of File objects
54
"""
55
56
@property
57
def args(self) -> dict:
58
"""
59
Query string arguments.
60
61
Returns:
62
Dictionary of query parameters
63
"""
64
65
@property
66
def raw_args(self) -> dict:
67
"""Raw query string arguments without processing."""
68
69
@property
70
def query_args(self) -> list:
71
"""
72
Query arguments as list of tuples.
73
74
Returns:
75
List of (key, value) tuples
76
"""
77
78
@property
79
def headers(self):
80
"""
81
Request headers.
82
83
Returns:
84
Header dictionary
85
"""
86
87
@property
88
def method(self) -> str:
89
"""HTTP method (GET, POST, etc.)."""
90
91
@property
92
def ip(self) -> str:
93
"""Client IP address."""
94
95
@property
96
def forwarded(self) -> dict:
97
"""Forwarded headers information."""
98
99
@property
100
def remote_addr(self) -> str:
101
"""Remote client address."""
102
103
@property
104
def scheme(self) -> str:
105
"""Request scheme (http or https)."""
106
107
@property
108
def host(self) -> str:
109
"""Request host header."""
110
111
@property
112
def path(self) -> str:
113
"""Request path without query string."""
114
115
@property
116
def query_string(self) -> str:
117
"""Raw query string."""
118
119
@property
120
def url(self) -> str:
121
"""Complete request URL."""
122
123
@property
124
def token(self) -> str:
125
"""Authorization token from Authorization header."""
126
127
@property
128
def match_info(self) -> dict:
129
"""Route match information and parameters."""
130
131
@property
132
def stream(self):
133
"""Request stream for handling large uploads."""
134
135
@property
136
def ctx(self):
137
"""Request context object for storing custom data."""
138
139
def get_args(
140
self,
141
key: str,
142
default=None,
143
type=str
144
):
145
"""
146
Get query argument with type conversion.
147
148
Parameters:
149
- key: Argument name
150
- default: Default value if not found
151
- type: Type conversion function
152
153
Returns:
154
Converted argument value
155
"""
156
157
def get_query_args(self, key: str, default=None):
158
"""Alias for get_args method."""
159
160
def get_form(self, key: str, default=None):
161
"""
162
Get form field value.
163
164
Parameters:
165
- key: Form field name
166
- default: Default value if not found
167
168
Returns:
169
Form field value
170
"""
171
172
def get_files(self, key: str, default=None):
173
"""
174
Get uploaded file.
175
176
Parameters:
177
- key: File field name
178
- default: Default value if not found
179
180
Returns:
181
File object or default
182
"""
183
184
def url_for(self, view_name: str, **kwargs) -> str:
185
"""
186
Generate URL for named route.
187
188
Parameters:
189
- view_name: Route name
190
- **kwargs: URL parameters
191
192
Returns:
193
Generated URL
194
"""
195
196
async def receive_body(self) -> bytes:
197
"""
198
Receive request body asynchronously.
199
200
Returns:
201
Request body bytes
202
"""
203
```
204
205
### Response Functions
206
207
Factory functions for creating HTTP responses with different content types and behaviors.
208
209
```python { .api }
210
def json(
211
body: Any,
212
status: int = 200,
213
headers: Optional[dict[str, str]] = None,
214
content_type: str = "application/json",
215
dumps: Optional[Callable[..., AnyStr]] = None,
216
**kwargs: Any,
217
):
218
"""
219
Create JSON response.
220
221
Parameters:
222
- body: Data to serialize as JSON
223
- status: HTTP status code
224
- headers: Additional headers
225
- content_type: Response content type
226
- dumps: Custom JSON serializer
227
228
Returns:
229
HTTPResponse with JSON content
230
"""
231
232
def text(
233
body: str,
234
status: int = 200,
235
headers: dict = None,
236
content_type: str = "text/plain; charset=utf-8",
237
**kwargs
238
):
239
"""
240
Create plain text response.
241
242
Parameters:
243
- body: Text content
244
- status: HTTP status code
245
- headers: Additional headers
246
- content_type: Response content type
247
248
Returns:
249
HTTPResponse with text content
250
"""
251
252
def html(
253
body: str,
254
status: int = 200,
255
headers: dict = None,
256
**kwargs
257
):
258
"""
259
Create HTML response.
260
261
Parameters:
262
- body: HTML content
263
- status: HTTP status code
264
- headers: Additional headers
265
266
Returns:
267
HTTPResponse with HTML content
268
"""
269
270
def raw(
271
body: bytes,
272
status: int = 200,
273
headers: dict = None,
274
content_type: str = "application/octet-stream",
275
**kwargs
276
):
277
"""
278
Create raw bytes response.
279
280
Parameters:
281
- body: Raw bytes content
282
- status: HTTP status code
283
- headers: Additional headers
284
- content_type: Response content type
285
286
Returns:
287
HTTPResponse with raw content
288
"""
289
290
def redirect(
291
to: str,
292
status: int = 302,
293
headers: dict = None,
294
**kwargs
295
):
296
"""
297
Create redirect response.
298
299
Parameters:
300
- to: Redirect URL
301
- status: HTTP redirect status code (301, 302, 303, 307, 308)
302
- headers: Additional headers
303
304
Returns:
305
HTTPResponse with redirect
306
"""
307
308
def file(
309
location: str,
310
status: int = 200,
311
mime_type: str = None,
312
headers: dict = None,
313
filename: str = None,
314
**kwargs
315
):
316
"""
317
Create file response.
318
319
Parameters:
320
- location: File path
321
- status: HTTP status code
322
- mime_type: File MIME type
323
- headers: Additional headers
324
- filename: Download filename
325
326
Returns:
327
FileResponse for serving files
328
"""
329
330
def empty(
331
status: int = 204,
332
headers: Optional[dict[str, str]] = None,
333
):
334
"""
335
Create empty response.
336
337
Parameters:
338
- status: HTTP status code
339
- headers: Additional headers
340
341
Returns:
342
HTTPResponse with no content
343
"""
344
```
345
346
### HTTPResponse Class
347
348
The base response class that all response functions return, providing response manipulation and sending capabilities.
349
350
```python { .api }
351
class HTTPResponse:
352
"""HTTP response object."""
353
354
def __init__(
355
self,
356
body: bytes = None,
357
status: int = 200,
358
headers: dict = None,
359
content_type: str = None,
360
**kwargs
361
):
362
"""
363
Initialize HTTP response.
364
365
Parameters:
366
- body: Response body
367
- status: HTTP status code
368
- headers: Response headers
369
- content_type: Content type header
370
"""
371
372
@property
373
def body(self) -> bytes:
374
"""Response body as bytes."""
375
376
@property
377
def status(self) -> int:
378
"""HTTP status code."""
379
380
@property
381
def content_type(self) -> str:
382
"""Response content type."""
383
384
@property
385
def headers(self):
386
"""Response headers object."""
387
388
@property
389
def cookies(self):
390
"""Response cookies."""
391
392
async def send(
393
self,
394
data: bytes = None,
395
end_stream: bool = None
396
):
397
"""
398
Send response data.
399
400
Parameters:
401
- data: Data to send
402
- end_stream: Whether to end the stream
403
"""
404
405
def stream(
406
self,
407
request,
408
write_buffer_size: int = 4096,
409
**kwargs
410
):
411
"""
412
Stream response data.
413
414
Parameters:
415
- request: Request object
416
- write_buffer_size: Buffer size for writing
417
"""
418
```
419
420
### Streaming Responses
421
422
Handle large responses and real-time data streaming with streaming response capabilities.
423
424
```python { .api }
425
class StreamingHTTPResponse(HTTPResponse):
426
"""Streaming HTTP response for large content."""
427
428
def __init__(
429
self,
430
streaming_fn,
431
status: int = 200,
432
headers: dict = None,
433
content_type: str = "text/plain",
434
**kwargs
435
):
436
"""
437
Initialize streaming response.
438
439
Parameters:
440
- streaming_fn: Async function that yields data
441
- status: HTTP status code
442
- headers: Response headers
443
- content_type: Content type
444
"""
445
446
class ResponseStream:
447
"""Helper for streaming responses."""
448
449
async def write(self, data: bytes):
450
"""
451
Write data to stream.
452
453
Parameters:
454
- data: Data bytes to write
455
"""
456
457
async def end(self):
458
"""End the stream."""
459
```
460
461
### File Uploads
462
463
Handle uploaded files through the request.files interface.
464
465
```python { .api }
466
class File:
467
"""Uploaded file object."""
468
469
@property
470
def name(self) -> str:
471
"""Original filename."""
472
473
@property
474
def type(self) -> str:
475
"""File content type."""
476
477
@property
478
def body(self) -> bytes:
479
"""File content as bytes."""
480
481
def save(self, location: str):
482
"""
483
Save file to disk.
484
485
Parameters:
486
- location: Save path
487
"""
488
```
489
490
## Usage Examples
491
492
### Request Data Access
493
494
```python
495
from sanic import Sanic
496
from sanic.response import json
497
498
app = Sanic("MyApp")
499
500
@app.route("/api/data", methods=["POST"])
501
async def handle_data(request):
502
# Access different types of request data
503
json_data = request.json
504
form_data = request.form
505
files = request.files
506
query_params = request.args
507
headers = request.headers
508
509
# Process uploaded files
510
if "upload" in files:
511
uploaded_file = files["upload"]
512
uploaded_file.save(f"/uploads/{uploaded_file.name}")
513
514
return json({
515
"received_json": json_data,
516
"form_fields": list(form_data.keys()),
517
"query_params": dict(query_params),
518
"content_type": request.content_type,
519
"client_ip": request.ip
520
})
521
```
522
523
### Response Generation
524
525
```python
526
from sanic.response import json, text, html, redirect, file
527
528
@app.route("/api/users/<user_id:int>")
529
async def get_user(request, user_id):
530
user = await fetch_user(user_id)
531
if not user:
532
return json({"error": "User not found"}, status=404)
533
return json({"user": user})
534
535
@app.route("/download/<filename>")
536
async def download_file(request, filename):
537
file_path = f"/files/{filename}"
538
return await file(file_path, filename=filename)
539
540
@app.route("/redirect")
541
async def redirect_example(request):
542
return redirect("/new-location", status=301)
543
544
@app.route("/streaming")
545
async def streaming_example(request):
546
async def generate_data():
547
for i in range(1000):
548
yield f"data chunk {i}\n".encode()
549
550
return StreamingHTTPResponse(generate_data)
551
```
552
553
### Custom Response Headers and Cookies
554
555
```python
556
from sanic.response import json
557
558
@app.route("/api/login", methods=["POST"])
559
async def login(request):
560
# Authenticate user
561
user = await authenticate(request.json)
562
563
response = json({"user": user["id"]})
564
565
# Set custom headers
566
response.headers["X-Custom-Header"] = "custom-value"
567
568
# Set cookies
569
response.cookies["session_token"] = user["token"]
570
response.cookies["session_token"]["httponly"] = True
571
response.cookies["session_token"]["secure"] = True
572
response.cookies["session_token"]["max-age"] = 3600
573
574
return response
575
```
576
577
### Request Streaming
578
579
```python
580
@app.route("/upload-large", methods=["POST"], stream=True)
581
async def upload_large_file(request):
582
"""Handle large file uploads with streaming."""
583
584
async def save_chunks():
585
with open("/tmp/uploaded_file", "wb") as f:
586
async for body in request.stream:
587
f.write(body)
588
589
await save_chunks()
590
return json({"status": "uploaded"})
591
```