0
# Request and Response Handling
1
2
Flask provides Request and Response classes for handling HTTP data. The Request object contains all incoming HTTP data, while the Response object represents the HTTP response sent back to the client.
3
4
## Capabilities
5
6
### Request Object
7
8
The Request object contains all data from the incoming HTTP request.
9
10
```python { .api }
11
class Request:
12
# HTTP method and URL information
13
method: str # HTTP method (GET, POST, etc.)
14
url: str # Complete URL
15
base_url: str # URL without query string
16
url_root: str # Root URL (scheme + host + port)
17
path: str # URL path
18
query_string: bytes # Raw query string
19
full_path: str # Path + query string
20
21
# Request data
22
args: ImmutableMultiDict # URL query parameters
23
form: ImmutableMultiDict # Form data from POST/PUT
24
files: ImmutableMultiDict # Uploaded files
25
values: ImmutableMultiDict # Combined args and form data
26
json: Any # Parsed JSON data (if Content-Type is JSON)
27
data: bytes # Raw request body data
28
29
# Headers and metadata
30
headers: EnvironHeaders # HTTP headers
31
cookies: ImmutableMultiDict # Request cookies
32
content_type: str | None # Content-Type header
33
content_length: int | None # Content-Length header
34
mimetype: str # Main content type without parameters
35
36
# Remote client information
37
remote_addr: str | None # Client IP address
38
remote_user: str | None # Remote user (if authenticated)
39
40
# Flask-specific attributes
41
endpoint: str | None # Matched endpoint name
42
view_args: dict[str, Any] | None # URL rule variables
43
url_rule: Rule | None # Matched URL rule
44
blueprint: str | None # Blueprint name
45
46
# Environment and context
47
environ: dict # WSGI environment
48
shallow: bool # Whether request was created with shallow=True
49
50
def get_json(
51
self,
52
force: bool = False,
53
silent: bool = False,
54
cache: bool = True
55
) -> Any:
56
"""
57
Parse request data as JSON.
58
59
Args:
60
force: Parse even if Content-Type is not JSON
61
silent: Return None on parse errors instead of raising
62
cache: Cache parsed JSON for subsequent calls
63
64
Returns:
65
Parsed JSON data or None
66
67
Raises:
68
BadRequest: If JSON parsing fails and silent=False
69
"""
70
71
def get_data(self, cache: bool = True, as_text: bool = False, parse_form_data: bool = False) -> bytes | str:
72
"""
73
Get raw request body data.
74
75
Args:
76
cache: Cache data for subsequent calls
77
as_text: Return data as text string
78
parse_form_data: Parse form data from body
79
80
Returns:
81
Request body as bytes or string
82
"""
83
84
@property
85
def is_json(self) -> bool:
86
"""Check if request has JSON content type."""
87
88
@property
89
def is_secure(self) -> bool:
90
"""Check if request was made over HTTPS."""
91
92
@property
93
def is_xhr(self) -> bool:
94
"""Check if request was made via XMLHttpRequest (deprecated)."""
95
```
96
97
### Response Object
98
99
The Response object represents the HTTP response sent to the client.
100
101
```python { .api }
102
class Response:
103
def __init__(
104
self,
105
response: Any = None,
106
status: int | str | None = None,
107
headers: dict | list | None = None,
108
mimetype: str | None = None,
109
content_type: str | None = None,
110
direct_passthrough: bool = False
111
):
112
"""
113
Create a Response object.
114
115
Args:
116
response: Response data (string, bytes, or iterable)
117
status: HTTP status code or phrase
118
headers: Response headers
119
mimetype: Response MIME type
120
content_type: Complete Content-Type header
121
direct_passthrough: Pass response directly to WSGI server
122
"""
123
124
# Response data and status
125
data: bytes # Response body as bytes
126
status: str # HTTP status line
127
status_code: int # HTTP status code
128
129
# Headers
130
headers: Headers # Response headers
131
content_type: str | None # Content-Type header
132
content_length: int | None # Content-Length header
133
mimetype: str # Main content type
134
135
# Caching and cookies
136
cache_control: ResponseCacheControl # Cache-Control header
137
expires: datetime | None # Expires header
138
last_modified: datetime | None # Last-Modified header
139
etag: str | None # ETag header
140
vary: HeaderSet # Vary header
141
142
def set_cookie(
143
self,
144
key: str,
145
value: str = '',
146
max_age: int | None = None,
147
expires: datetime | str | None = None,
148
path: str | None = '/',
149
domain: str | None = None,
150
secure: bool = False,
151
httponly: bool = False,
152
samesite: str | None = None
153
) -> None:
154
"""
155
Set a cookie on the response.
156
157
Args:
158
key: Cookie name
159
value: Cookie value
160
max_age: Cookie max age in seconds
161
expires: Cookie expiration date
162
path: Cookie path
163
domain: Cookie domain
164
secure: Require HTTPS for cookie
165
httponly: Prevent JavaScript access
166
samesite: SameSite attribute ('Strict', 'Lax', or 'None')
167
"""
168
169
def delete_cookie(
170
self,
171
key: str,
172
path: str | None = '/',
173
domain: str | None = None,
174
secure: bool = False,
175
httponly: bool = False,
176
samesite: str | None = None
177
) -> None:
178
"""
179
Delete a cookie by setting it to expire immediately.
180
181
Args:
182
key: Cookie name to delete
183
path: Cookie path (must match original)
184
domain: Cookie domain (must match original)
185
secure: Secure flag (must match original)
186
httponly: HttpOnly flag (must match original)
187
samesite: SameSite flag (must match original)
188
"""
189
190
@property
191
def is_json(self) -> bool:
192
"""Check if response has JSON content type."""
193
194
def get_json(self, force: bool = False, silent: bool = False, cache: bool = True) -> Any:
195
"""
196
Parse response data as JSON.
197
198
Args:
199
force: Parse even if Content-Type is not JSON
200
silent: Return None on parse errors
201
cache: Cache parsed JSON
202
203
Returns:
204
Parsed JSON data or None
205
"""
206
```
207
208
### Response Creation Helpers
209
210
Functions for creating different types of responses.
211
212
```python { .api }
213
def make_response(*args) -> Response:
214
"""
215
Create a Response object from various inputs.
216
217
Args:
218
*args: Response data, status, headers in various combinations
219
220
Returns:
221
Response object
222
223
Examples:
224
make_response('Hello')
225
make_response('Hello', 200)
226
make_response('Error', 404, {'Content-Type': 'text/plain'})
227
make_response(('Hello', 200, {'X-Custom': 'value'}))
228
"""
229
```
230
231
## Usage Examples
232
233
### Accessing Request Data
234
235
```python
236
from flask import Flask, request, jsonify
237
238
app = Flask(__name__)
239
240
@app.route('/info')
241
def request_info():
242
return {
243
'method': request.method,
244
'url': request.url,
245
'path': request.path,
246
'args': dict(request.args),
247
'headers': dict(request.headers),
248
'remote_addr': request.remote_addr,
249
'is_secure': request.is_secure,
250
'is_json': request.is_json
251
}
252
253
@app.route('/query')
254
def query_params():
255
# Get single value
256
name = request.args.get('name', 'Unknown')
257
258
# Get multiple values for same key
259
tags = request.args.getlist('tag')
260
261
# Get with type conversion
262
page = request.args.get('page', 1, type=int)
263
264
return {
265
'name': name,
266
'tags': tags,
267
'page': page
268
}
269
```
270
271
### Handling Form Data
272
273
```python
274
from flask import Flask, request, render_template
275
276
app = Flask(__name__)
277
278
@app.route('/form', methods=['GET', 'POST'])
279
def form_handler():
280
if request.method == 'GET':
281
return render_template('form.html')
282
283
# Handle form submission
284
username = request.form.get('username')
285
email = request.form.get('email')
286
287
# Handle checkboxes (multiple values)
288
interests = request.form.getlist('interests')
289
290
# Validate required fields
291
if not username or not email:
292
return 'Username and email are required', 400
293
294
return f'Hello {username}! Email: {email}, Interests: {interests}'
295
296
@app.route('/upload', methods=['POST'])
297
def file_upload():
298
if 'file' not in request.files:
299
return 'No file uploaded', 400
300
301
file = request.files['file']
302
if file.filename == '':
303
return 'No file selected', 400
304
305
if file:
306
# Save file
307
filename = secure_filename(file.filename)
308
file.save(os.path.join('uploads', filename))
309
return f'File {filename} uploaded successfully'
310
```
311
312
### JSON Request Handling
313
314
```python
315
from flask import Flask, request, jsonify
316
317
app = Flask(__name__)
318
319
@app.route('/api/user', methods=['POST'])
320
def create_user():
321
# Check if request contains JSON
322
if not request.is_json:
323
return {'error': 'Content-Type must be application/json'}, 400
324
325
# Get JSON data
326
data = request.get_json()
327
328
# Validate required fields
329
required_fields = ['name', 'email']
330
for field in required_fields:
331
if field not in data:
332
return {'error': f'Missing field: {field}'}, 400
333
334
# Process user creation
335
user = {
336
'id': 123,
337
'name': data['name'],
338
'email': data['email'],
339
'created': '2023-01-01T00:00:00Z'
340
}
341
342
return jsonify(user), 201
343
344
@app.route('/api/data', methods=['PUT'])
345
def update_data():
346
try:
347
data = request.get_json(force=True)
348
except Exception:
349
return {'error': 'Invalid JSON'}, 400
350
351
return {'message': 'Data updated', 'received': data}
352
```
353
354
### Creating Custom Responses
355
356
```python
357
from flask import Flask, make_response, jsonify, render_template
358
from datetime import datetime, timedelta
359
360
app = Flask(__name__)
361
362
@app.route('/custom')
363
def custom_response():
364
# Create response with custom headers
365
response = make_response('Custom response content')
366
response.headers['X-Custom-Header'] = 'Custom Value'
367
response.status_code = 200
368
return response
369
370
@app.route('/json-custom')
371
def json_custom():
372
data = {'message': 'Hello', 'timestamp': datetime.now().isoformat()}
373
response = make_response(jsonify(data))
374
response.headers['X-API-Version'] = '1.0'
375
return response
376
377
@app.route('/template-custom')
378
def template_custom():
379
html = render_template('page.html', title='Custom Page')
380
response = make_response(html)
381
response.headers['X-Generated'] = 'Flask'
382
return response
383
384
@app.route('/download')
385
def download_file():
386
data = 'File content here'
387
response = make_response(data)
388
response.headers['Content-Type'] = 'application/octet-stream'
389
response.headers['Content-Disposition'] = 'attachment; filename=data.txt'
390
return response
391
```
392
393
### Cookie Handling
394
395
```python
396
from flask import Flask, request, make_response
397
from datetime import datetime, timedelta
398
399
app = Flask(__name__)
400
401
@app.route('/set-cookie')
402
def set_cookie():
403
response = make_response('Cookie set!')
404
405
# Simple cookie
406
response.set_cookie('username', 'john')
407
408
# Cookie with expiration
409
expires = datetime.now() + timedelta(days=30)
410
response.set_cookie('session_id', 'abc123', expires=expires)
411
412
# Secure cookie
413
response.set_cookie(
414
'secure_token',
415
'secret_value',
416
secure=True,
417
httponly=True,
418
samesite='Strict'
419
)
420
421
return response
422
423
@app.route('/get-cookie')
424
def get_cookie():
425
username = request.cookies.get('username', 'Guest')
426
session_id = request.cookies.get('session_id')
427
428
return {
429
'username': username,
430
'session_id': session_id,
431
'all_cookies': dict(request.cookies)
432
}
433
434
@app.route('/delete-cookie')
435
def delete_cookie():
436
response = make_response('Cookie deleted!')
437
response.delete_cookie('username')
438
return response
439
```
440
441
### Response Headers and Caching
442
443
```python
444
from flask import Flask, make_response
445
from datetime import datetime, timedelta
446
447
app = Flask(__name__)
448
449
@app.route('/cached')
450
def cached_response():
451
response = make_response('This response is cached')
452
453
# Set cache headers
454
response.cache_control.max_age = 3600 # 1 hour
455
response.cache_control.public = True
456
457
# Set ETag for conditional requests
458
response.set_etag('resource-v1')
459
460
# Set Last-Modified
461
response.last_modified = datetime.now()
462
463
return response
464
465
@app.route('/no-cache')
466
def no_cache_response():
467
response = make_response('This response is not cached')
468
469
# Prevent caching
470
response.cache_control.no_cache = True
471
response.cache_control.no_store = True
472
response.cache_control.must_revalidate = True
473
474
# Set expiration in the past
475
response.expires = datetime.now() - timedelta(hours=1)
476
477
return response
478
479
@app.route('/api/cors')
480
def cors_response():
481
response = make_response({'message': 'CORS enabled'})
482
483
# CORS headers
484
response.headers['Access-Control-Allow-Origin'] = '*'
485
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
486
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
487
488
return response
489
```
490
491
### Error Responses
492
493
```python
494
from flask import Flask, request, jsonify, make_response
495
496
app = Flask(__name__)
497
498
@app.route('/api/users/<int:user_id>')
499
def get_user(user_id):
500
# Simulate user lookup
501
if user_id <= 0:
502
return {'error': 'Invalid user ID'}, 400
503
504
if user_id > 1000:
505
return {'error': 'User not found'}, 404
506
507
return {'id': user_id, 'name': f'User {user_id}'}
508
509
@app.errorhandler(400)
510
def bad_request(error):
511
return make_response(
512
jsonify({'error': 'Bad Request', 'message': str(error)}),
513
400,
514
{'Content-Type': 'application/json'}
515
)
516
517
@app.errorhandler(404)
518
def not_found(error):
519
if request.path.startswith('/api/'):
520
# JSON error for API routes
521
return jsonify({'error': 'Not Found'}), 404
522
else:
523
# HTML error for web routes
524
return render_template('404.html'), 404
525
526
@app.errorhandler(500)
527
def internal_error(error):
528
response = make_response('Internal Server Error', 500)
529
response.headers['X-Error-ID'] = 'ERR-12345'
530
return response
531
```