0
# JSON Support
1
2
Flask provides comprehensive JSON handling capabilities through the `flask.json` module, including serialization, deserialization, and response creation with Flask-specific enhancements.
3
4
## Capabilities
5
6
### JSON Response Creation
7
8
Function for creating JSON responses with proper headers and formatting.
9
10
```python { .api }
11
def jsonify(*args, **kwargs) -> Response:
12
"""
13
Create a JSON response from arguments.
14
15
Args:
16
*args: Positional arguments (single value or multiple values as array)
17
**kwargs: Keyword arguments (treated as object properties)
18
19
Returns:
20
Response object with JSON content and application/json mimetype
21
22
Examples:
23
jsonify(message="Hello")
24
jsonify([1, 2, 3])
25
jsonify({"key": "value"})
26
jsonify(users=[{"name": "John"}, {"name": "Jane"}])
27
"""
28
```
29
30
### JSON Serialization
31
32
Functions for converting Python objects to JSON strings.
33
34
```python { .api }
35
def dumps(obj: Any, **kwargs) -> str:
36
"""
37
Serialize object to JSON string.
38
39
Args:
40
obj: Object to serialize
41
**kwargs: Arguments passed to JSON encoder
42
43
Returns:
44
JSON string
45
46
Note:
47
Uses current app's JSON provider if available, otherwise standard json.dumps
48
"""
49
50
def dump(obj: Any, fp: IO[str], **kwargs) -> None:
51
"""
52
Serialize object to JSON and write to file.
53
54
Args:
55
obj: Object to serialize
56
fp: File-like object to write to
57
**kwargs: Arguments passed to JSON encoder
58
59
Note:
60
Uses current app's JSON provider if available, otherwise standard json.dump
61
"""
62
```
63
64
### JSON Deserialization
65
66
Functions for parsing JSON strings into Python objects.
67
68
```python { .api }
69
def loads(s: str | bytes, **kwargs) -> Any:
70
"""
71
Deserialize JSON string to Python object.
72
73
Args:
74
s: JSON string or bytes
75
**kwargs: Arguments passed to JSON decoder
76
77
Returns:
78
Deserialized Python object
79
80
Note:
81
Uses current app's JSON provider if available, otherwise standard json.loads
82
"""
83
84
def load(fp: IO[AnyStr], **kwargs) -> Any:
85
"""
86
Deserialize JSON from file to Python object.
87
88
Args:
89
fp: File-like object to read from
90
**kwargs: Arguments passed to JSON decoder
91
92
Returns:
93
Deserialized Python object
94
95
Note:
96
Uses current app's JSON provider if available, otherwise standard json.load
97
"""
98
```
99
100
### JSON Provider System
101
102
Classes for customizing JSON behavior in Flask applications.
103
104
```python { .api }
105
class JSONProvider:
106
"""Base class for JSON providers."""
107
108
def dumps(self, obj: Any, **kwargs) -> str:
109
"""Serialize object to JSON string."""
110
111
def loads(self, s: str | bytes, **kwargs) -> Any:
112
"""Deserialize JSON string to object."""
113
114
def dump(self, obj: Any, fp: IO[str], **kwargs) -> None:
115
"""Serialize object to JSON file."""
116
117
def load(self, fp: IO[AnyStr], **kwargs) -> Any:
118
"""Deserialize JSON from file."""
119
120
def response(self, *args, **kwargs) -> Response:
121
"""Create JSON response."""
122
123
class DefaultJSONProvider(JSONProvider):
124
"""Default JSON provider with Flask-specific enhancements."""
125
126
def __init__(self, app: Flask) -> None:
127
"""Initialize provider for Flask app."""
128
129
default: Callable[[Any], Any] | None # Default function for non-serializable objects
130
ensure_ascii: bool # Ensure ASCII output
131
sort_keys: bool # Sort object keys
132
compact: bool | None # Compact output format
133
mimetype: str # Response mimetype
134
```
135
136
### JSON Tag System
137
138
Classes for handling complex object serialization with tags.
139
140
```python { .api }
141
class JSONTag:
142
"""Base class for JSON object tags."""
143
144
key: str # Tag key identifier
145
146
def check(self, value: Any) -> bool:
147
"""Check if value should use this tag."""
148
149
def to_json(self, value: Any) -> Any:
150
"""Convert value to JSON-serializable form."""
151
152
def to_python(self, value: Any) -> Any:
153
"""Convert JSON value back to Python object."""
154
155
class TaggedJSONSerializer:
156
"""Serializer that handles tagged objects."""
157
158
def __init__(self) -> None:
159
"""Initialize serializer."""
160
161
def register(self, tag_class: type[JSONTag], force: bool = False, index: int | None = None) -> None:
162
"""Register a tag class."""
163
164
def tag(self, value: Any) -> dict[str, Any]:
165
"""Tag a value for serialization."""
166
167
def untag(self, value: dict[str, Any]) -> Any:
168
"""Untag a value during deserialization."""
169
170
def dumps(self, value: Any, **kwargs) -> str:
171
"""Serialize with tagging."""
172
173
def loads(self, value: str, **kwargs) -> Any:
174
"""Deserialize with untagging."""
175
```
176
177
## Usage Examples
178
179
### Basic JSON Responses
180
181
```python
182
from flask import Flask, jsonify, request
183
184
app = Flask(__name__)
185
186
@app.route('/api/user/<int:user_id>')
187
def get_user(user_id):
188
# Simple JSON response
189
user = {
190
'id': user_id,
191
'name': f'User {user_id}',
192
'email': f'user{user_id}@example.com'
193
}
194
return jsonify(user)
195
196
@app.route('/api/users')
197
def get_users():
198
# JSON array response
199
users = [
200
{'id': 1, 'name': 'John'},
201
{'id': 2, 'name': 'Jane'},
202
{'id': 3, 'name': 'Bob'}
203
]
204
return jsonify(users)
205
206
@app.route('/api/status')
207
def status():
208
# JSON with multiple keys
209
return jsonify(
210
status='ok',
211
version='1.0',
212
timestamp='2023-01-01T00:00:00Z'
213
)
214
215
@app.route('/api/message')
216
def message():
217
# Simple message
218
return jsonify(message='Hello, World!')
219
```
220
221
### JSON Request Handling
222
223
```python
224
from flask import Flask, request, jsonify
225
import json
226
227
app = Flask(__name__)
228
229
@app.route('/api/users', methods=['POST'])
230
def create_user():
231
# Get JSON data from request
232
if not request.is_json:
233
return jsonify(error='Content-Type must be application/json'), 400
234
235
data = request.get_json()
236
237
# Validate required fields
238
required_fields = ['name', 'email']
239
for field in required_fields:
240
if field not in data:
241
return jsonify(error=f'Missing field: {field}'), 400
242
243
# Create user (simulate)
244
user = {
245
'id': 123,
246
'name': data['name'],
247
'email': data['email'],
248
'created': '2023-01-01T00:00:00Z'
249
}
250
251
return jsonify(user), 201
252
253
@app.route('/api/bulk-upload', methods=['POST'])
254
def bulk_upload():
255
try:
256
data = request.get_json(force=True)
257
except Exception as e:
258
return jsonify(error='Invalid JSON'), 400
259
260
if not isinstance(data, list):
261
return jsonify(error='Expected JSON array'), 400
262
263
results = []
264
for item in data:
265
# Process each item
266
results.append({
267
'id': item.get('id'),
268
'status': 'processed'
269
})
270
271
return jsonify(results=results, count=len(results))
272
```
273
274
### Custom JSON Serialization
275
276
```python
277
from flask import Flask, jsonify
278
from datetime import datetime, date
279
from decimal import Decimal
280
import uuid
281
282
app = Flask(__name__)
283
284
# Custom JSON encoder for special types
285
def custom_json_default(obj):
286
"""Custom JSON serialization for unsupported types."""
287
if isinstance(obj, datetime):
288
return obj.isoformat()
289
elif isinstance(obj, date):
290
return obj.isoformat()
291
elif isinstance(obj, Decimal):
292
return float(obj)
293
elif isinstance(obj, uuid.UUID):
294
return str(obj)
295
elif hasattr(obj, 'to_dict'):
296
return obj.to_dict()
297
298
raise TypeError(f'Object of type {type(obj)} is not JSON serializable')
299
300
# Configure the app's JSON provider
301
app.json.default = custom_json_default
302
303
class User:
304
def __init__(self, id, name, created):
305
self.id = id
306
self.name = name
307
self.created = created
308
309
def to_dict(self):
310
return {
311
'id': self.id,
312
'name': self.name,
313
'created': self.created
314
}
315
316
@app.route('/api/advanced')
317
def advanced_json():
318
data = {
319
'timestamp': datetime.now(),
320
'date': date.today(),
321
'price': Decimal('19.99'),
322
'uuid': uuid.uuid4(),
323
'user': User(1, 'John', datetime.now())
324
}
325
326
return jsonify(data)
327
```
328
329
### JSON Configuration
330
331
```python
332
from flask import Flask, jsonify
333
334
app = Flask(__name__)
335
336
# Configure JSON behavior
337
app.json.ensure_ascii = False # Allow Unicode characters
338
app.json.sort_keys = True # Sort object keys
339
app.json.compact = True # Use compact representation
340
341
@app.route('/api/unicode')
342
def unicode_response():
343
return jsonify(
344
message='Hello, 世界! 🌍',
345
emoji='🚀',
346
chinese='你好'
347
)
348
349
@app.route('/api/pretty')
350
def pretty_json():
351
# Override compact setting for this response
352
data = {
353
'users': [
354
{'name': 'Alice', 'age': 30},
355
{'name': 'Bob', 'age': 25}
356
],
357
'meta': {
358
'total': 2,
359
'page': 1
360
}
361
}
362
363
# Create pretty-printed JSON
364
import json
365
pretty_json = json.dumps(data, indent=2, sort_keys=True)
366
367
from flask import Response
368
return Response(
369
pretty_json,
370
mimetype='application/json'
371
)
372
```
373
374
### Error Handling with JSON
375
376
```python
377
from flask import Flask, jsonify, request
378
import logging
379
380
app = Flask(__name__)
381
382
@app.errorhandler(400)
383
def bad_request(error):
384
return jsonify(
385
error='Bad Request',
386
message=str(error),
387
status_code=400
388
), 400
389
390
@app.errorhandler(404)
391
def not_found(error):
392
return jsonify(
393
error='Not Found',
394
message='The requested resource was not found',
395
status_code=404
396
), 404
397
398
@app.errorhandler(500)
399
def internal_error(error):
400
app.logger.error(f'Server Error: {error}')
401
return jsonify(
402
error='Internal Server Error',
403
message='An unexpected error occurred',
404
status_code=500
405
), 500
406
407
@app.route('/api/error-test')
408
def error_test():
409
error_type = request.args.get('type', 'none')
410
411
if error_type == '400':
412
from flask import abort
413
abort(400, description="Test bad request")
414
elif error_type == '404':
415
abort(404)
416
elif error_type == '500':
417
raise Exception("Test internal error")
418
419
return jsonify(message='No error')
420
```
421
422
### Streaming JSON
423
424
```python
425
from flask import Flask, Response, stream_with_context
426
import json
427
import time
428
429
app = Flask(__name__)
430
431
@app.route('/api/stream')
432
def stream_json():
433
def generate_data():
434
yield '{"items": ['
435
436
for i in range(100):
437
if i > 0:
438
yield ','
439
440
item = {
441
'id': i,
442
'name': f'Item {i}',
443
'timestamp': time.time()
444
}
445
446
yield json.dumps(item)
447
time.sleep(0.1) # Simulate processing
448
449
yield ']}'
450
451
return Response(
452
stream_with_context(generate_data()),
453
mimetype='application/json'
454
)
455
456
@app.route('/api/json-lines')
457
def json_lines():
458
"""Stream JSON Lines format (one JSON object per line)."""
459
def generate_lines():
460
for i in range(50):
461
item = {
462
'id': i,
463
'data': f'Record {i}',
464
'processed_at': time.time()
465
}
466
yield json.dumps(item) + '\n'
467
time.sleep(0.2)
468
469
return Response(
470
stream_with_context(generate_lines()),
471
mimetype='application/x-ndjson'
472
)
473
```
474
475
### Custom JSON Provider
476
477
```python
478
from flask import Flask
479
from flask.json.provider import DefaultJSONProvider
480
import orjson # Fast JSON library
481
482
class OrjsonProvider(DefaultJSONProvider):
483
"""Custom JSON provider using orjson for better performance."""
484
485
def dumps(self, obj, **kwargs):
486
# orjson returns bytes, so decode to string
487
return orjson.dumps(obj).decode('utf-8')
488
489
def loads(self, s, **kwargs):
490
return orjson.loads(s)
491
492
app = Flask(__name__)
493
app.json = OrjsonProvider(app)
494
495
@app.route('/api/fast')
496
def fast_json():
497
# Large data structure
498
data = {
499
'items': [{'id': i, 'value': f'item_{i}'} for i in range(1000)]
500
}
501
502
from flask import jsonify
503
return jsonify(data)
504
```
505
506
### JSON Schema Validation
507
508
```python
509
from flask import Flask, request, jsonify
510
import jsonschema
511
from jsonschema import validate, ValidationError
512
513
app = Flask(__name__)
514
515
# Define JSON schemas
516
USER_SCHEMA = {
517
"type": "object",
518
"properties": {
519
"name": {"type": "string", "minLength": 1},
520
"email": {"type": "string", "format": "email"},
521
"age": {"type": "integer", "minimum": 0, "maximum": 150}
522
},
523
"required": ["name", "email"],
524
"additionalProperties": False
525
}
526
527
def validate_json(schema):
528
"""Decorator to validate JSON against schema."""
529
def decorator(f):
530
def wrapper(*args, **kwargs):
531
try:
532
validate(request.get_json(), schema)
533
except ValidationError as e:
534
return jsonify(
535
error="Validation Error",
536
message=e.message,
537
path=list(e.path)
538
), 400
539
except Exception as e:
540
return jsonify(error="Invalid JSON"), 400
541
542
return f(*args, **kwargs)
543
544
wrapper.__name__ = f.__name__
545
return wrapper
546
return decorator
547
548
@app.route('/api/users', methods=['POST'])
549
@validate_json(USER_SCHEMA)
550
def create_user_validated():
551
data = request.get_json()
552
553
# Data is now guaranteed to be valid
554
user = {
555
'id': 123,
556
'name': data['name'],
557
'email': data['email'],
558
'age': data.get('age')
559
}
560
561
return jsonify(user), 201
562
```