0
# Media Processing
1
2
Pluggable media handling system for serializing and deserializing request/response bodies. Supports JSON, MessagePack, multipart forms, URL-encoded data, and custom media types with extensible handler architecture.
3
4
## Capabilities
5
6
### Base Media Handler Classes
7
8
Foundation classes for implementing custom media processors.
9
10
```python { .api }
11
class BaseHandler:
12
def serialize(self, media: object, content_type: str) -> bytes:
13
"""
14
Serialize Python object to bytes.
15
16
Args:
17
media: Python object to serialize
18
content_type: MIME content type
19
20
Returns:
21
Serialized bytes
22
"""
23
24
def deserialize(self, stream: object, content_type: str, content_length: int) -> object:
25
"""
26
Deserialize bytes stream to Python object.
27
28
Args:
29
stream: Input byte stream
30
content_type: MIME content type
31
content_length: Content length in bytes
32
33
Returns:
34
Deserialized Python object
35
"""
36
37
class TextBaseHandlerWS:
38
def serialize(self, media: object) -> str:
39
"""
40
Serialize Python object to text for WebSocket.
41
42
Args:
43
media: Python object to serialize
44
45
Returns:
46
Serialized text string
47
"""
48
49
def deserialize(self, payload: str) -> object:
50
"""
51
Deserialize text payload to Python object.
52
53
Args:
54
payload: Text payload from WebSocket
55
56
Returns:
57
Deserialized Python object
58
"""
59
60
class BinaryBaseHandlerWS:
61
def serialize(self, media: object) -> bytes:
62
"""
63
Serialize Python object to bytes for WebSocket.
64
65
Args:
66
media: Python object to serialize
67
68
Returns:
69
Serialized bytes
70
"""
71
72
def deserialize(self, payload: bytes) -> object:
73
"""
74
Deserialize binary payload to Python object.
75
76
Args:
77
payload: Binary payload from WebSocket
78
79
Returns:
80
Deserialized Python object
81
"""
82
```
83
84
### Media Handler Registry
85
86
Central registry for managing media type handlers and content negotiation.
87
88
```python { .api }
89
class Handlers:
90
def __init__(self, initial: dict = None):
91
"""
92
Create media handler registry.
93
94
Args:
95
initial: Initial handler mappings {media_type: handler}
96
"""
97
98
def find_by_media_type(self, media_type: str, default: object = None) -> BaseHandler:
99
"""
100
Find handler for specific media type.
101
102
Args:
103
media_type: MIME media type (e.g., 'application/json')
104
default: Default handler if none found
105
106
Returns:
107
Media handler instance or default
108
"""
109
110
def __setitem__(self, media_type: str, handler: BaseHandler):
111
"""
112
Register handler for media type.
113
114
Args:
115
media_type: MIME media type
116
handler: Handler instance
117
"""
118
119
def __getitem__(self, media_type: str) -> BaseHandler:
120
"""
121
Get handler for media type.
122
123
Args:
124
media_type: MIME media type
125
126
Returns:
127
Handler instance
128
"""
129
130
class MissingDependencyHandler:
131
def __init__(self, library: str, media_type: str):
132
"""
133
Placeholder handler when dependencies are missing.
134
135
Args:
136
library: Name of missing library
137
media_type: Media type this handler would support
138
"""
139
140
def serialize(self, media: object, content_type: str = None) -> bytes:
141
"""Raises error about missing dependency"""
142
143
def deserialize(self, stream: object, content_type: str, content_length: int) -> object:
144
"""Raises error about missing dependency"""
145
```
146
147
#### Handler Registry Usage
148
149
```python
150
import falcon
151
152
# Create custom handlers registry
153
handlers = falcon.media.Handlers({
154
'application/json': falcon.media.JSONHandler(),
155
'application/msgpack': falcon.media.MessagePackHandler(),
156
})
157
158
# Configure app with custom handlers
159
req_options = falcon.RequestOptions(media_handlers=handlers)
160
resp_options = falcon.ResponseOptions(media_handlers=handlers)
161
162
app = falcon.App(
163
req_options=req_options,
164
resp_options=resp_options
165
)
166
```
167
168
### Built-in JSON Handler
169
170
High-performance JSON serialization and deserialization using standard library or orjson.
171
172
```python { .api }
173
class JSONHandler(BaseHandler):
174
def __init__(self, loads: callable = None, dumps: callable = None):
175
"""
176
JSON media handler.
177
178
Args:
179
loads: Custom JSON decoder function
180
dumps: Custom JSON encoder function
181
"""
182
183
def serialize(self, media: object, content_type: str = None) -> bytes:
184
"""
185
Serialize Python object to JSON bytes.
186
187
Args:
188
media: Python object (dict, list, etc.)
189
content_type: Content type (ignored)
190
191
Returns:
192
JSON bytes
193
"""
194
195
def deserialize(self, stream: object, content_type: str, content_length: int) -> object:
196
"""
197
Deserialize JSON bytes to Python object.
198
199
Args:
200
stream: JSON byte stream
201
content_type: Content type (ignored)
202
content_length: Content length
203
204
Returns:
205
Python object
206
"""
207
208
class JSONHandlerWS(TextBaseHandlerWS):
209
def __init__(self, loads: callable = None, dumps: callable = None):
210
"""
211
JSON WebSocket handler.
212
213
Args:
214
loads: Custom JSON decoder function
215
dumps: Custom JSON encoder function
216
"""
217
```
218
219
### MessagePack Handler
220
221
Efficient MessagePack binary serialization support.
222
223
```python { .api }
224
class MessagePackHandler(BaseHandler):
225
def __init__(self, **kwargs):
226
"""
227
MessagePack media handler.
228
229
Args:
230
**kwargs: Additional options for msgpack
231
"""
232
233
def serialize(self, media: object, content_type: str = None) -> bytes:
234
"""
235
Serialize Python object to MessagePack bytes.
236
237
Args:
238
media: Python object
239
content_type: Content type (ignored)
240
241
Returns:
242
MessagePack bytes
243
"""
244
245
def deserialize(self, stream: object, content_type: str, content_length: int) -> object:
246
"""
247
Deserialize MessagePack bytes to Python object.
248
249
Args:
250
stream: MessagePack byte stream
251
content_type: Content type (ignored)
252
content_length: Content length
253
254
Returns:
255
Python object
256
"""
257
258
class MessagePackHandlerWS(BinaryBaseHandlerWS):
259
def __init__(self, **kwargs):
260
"""
261
MessagePack WebSocket handler.
262
263
Args:
264
**kwargs: Additional options for msgpack
265
"""
266
```
267
268
### Multipart Form Handler
269
270
Support for multipart/form-data file uploads and form processing.
271
272
```python { .api }
273
class MultipartFormHandler(BaseHandler):
274
def __init__(self):
275
"""Multipart form data handler."""
276
277
def serialize(self, media: object, content_type: str = None) -> bytes:
278
"""
279
Serialize form data to multipart bytes.
280
281
Args:
282
media: Form data dictionary
283
content_type: Content type with boundary
284
285
Returns:
286
Multipart bytes
287
"""
288
289
def deserialize(self, stream: object, content_type: str, content_length: int) -> object:
290
"""
291
Parse multipart form data from stream.
292
293
Args:
294
stream: Multipart byte stream
295
content_type: Content type with boundary parameter
296
content_length: Content length
297
298
Returns:
299
Form data dictionary
300
"""
301
```
302
303
#### Multipart Usage Example
304
305
```python
306
class FileUploadResource:
307
def on_post(self, req, resp):
308
"""Handle file upload"""
309
# req.media contains parsed multipart data
310
form_data = req.media
311
312
# Access uploaded file
313
uploaded_file = form_data.get('file')
314
if uploaded_file:
315
# Process file upload
316
filename = uploaded_file.filename
317
content_type = uploaded_file.content_type
318
file_data = uploaded_file.data # or use .stream
319
320
# Save file
321
save_uploaded_file(filename, file_data)
322
323
resp.status = falcon.HTTP_201
324
resp.media = {'uploaded': filename}
325
else:
326
raise falcon.HTTPBadRequest(
327
title='Missing file',
328
description='No file provided in upload'
329
)
330
```
331
332
### URL-Encoded Form Handler
333
334
Support for application/x-www-form-urlencoded form data.
335
336
```python { .api }
337
class URLEncodedFormHandler(BaseHandler):
338
def __init__(self):
339
"""URL-encoded form handler."""
340
341
def serialize(self, media: object, content_type: str = None) -> bytes:
342
"""
343
Serialize form data to URL-encoded bytes.
344
345
Args:
346
media: Form data dictionary
347
content_type: Content type (ignored)
348
349
Returns:
350
URL-encoded bytes
351
"""
352
353
def deserialize(self, stream: object, content_type: str, content_length: int) -> object:
354
"""
355
Parse URL-encoded form data from stream.
356
357
Args:
358
stream: URL-encoded byte stream
359
content_type: Content type (ignored)
360
content_length: Content length
361
362
Returns:
363
Form data dictionary
364
"""
365
```
366
367
### Media Validation
368
369
JSON Schema validation support for request/response media.
370
371
```python { .api }
372
# Validation support (falcon.media.validators.jsonschema module)
373
def validate(schema: dict) -> callable:
374
"""
375
Create JSON Schema validator decorator.
376
377
Args:
378
schema: JSON Schema dictionary
379
380
Returns:
381
Decorator function for validation
382
"""
383
```
384
385
#### Validation Example
386
387
```python
388
from falcon.media.validators import jsonschema
389
390
user_schema = {
391
'type': 'object',
392
'properties': {
393
'name': {'type': 'string', 'minLength': 1},
394
'email': {'type': 'string', 'format': 'email'},
395
'age': {'type': 'integer', 'minimum': 0}
396
},
397
'required': ['name', 'email']
398
}
399
400
class UserResource:
401
@jsonschema.validate(req_schema=user_schema)
402
def on_post(self, req, resp):
403
# req.media is automatically validated against schema
404
user_data = req.media
405
new_user = create_user(user_data)
406
resp.status = falcon.HTTP_201
407
resp.media = new_user
408
```
409
410
### Custom Media Handler
411
412
Creating custom media handlers for specialized content types.
413
414
```python { .api }
415
class CustomHandler(BaseHandler):
416
def __init__(self, **options):
417
"""
418
Custom media handler implementation.
419
420
Args:
421
**options: Handler-specific options
422
"""
423
424
def serialize(self, media: object, content_type: str = None) -> bytes:
425
"""Implement custom serialization logic"""
426
427
def deserialize(self, stream: object, content_type: str, content_length: int) -> object:
428
"""Implement custom deserialization logic"""
429
```
430
431
#### Custom Handler Example
432
433
```python
434
import yaml
435
import falcon
436
437
class YAMLHandler(falcon.media.BaseHandler):
438
"""Custom YAML media handler"""
439
440
def serialize(self, media, content_type=None):
441
"""Serialize Python object to YAML"""
442
return yaml.dump(media, default_flow_style=False).encode('utf-8')
443
444
def deserialize(self, stream, content_type, content_length):
445
"""Deserialize YAML to Python object"""
446
data = stream.read(content_length).decode('utf-8')
447
return yaml.safe_load(data)
448
449
# Register custom handler
450
app = falcon.App()
451
app.req_options.media_handlers['application/yaml'] = YAMLHandler()
452
app.resp_options.media_handlers['application/yaml'] = YAMLHandler()
453
454
class YAMLResource:
455
def on_post(self, req, resp):
456
# Automatically uses YAML handler based on Content-Type
457
data = req.media # YAML parsed to Python object
458
resp.content_type = 'application/yaml'
459
resp.media = {'processed': data} # Python object serialized to YAML
460
```
461
462
### Error Handling
463
464
Media processing specific error classes for robust error handling.
465
466
```python { .api }
467
class MediaNotFoundError(Exception):
468
"""Raised when no media handler found for content type"""
469
470
class MediaMalformedError(Exception):
471
"""Raised when media content is malformed or invalid"""
472
473
class MediaValidationError(Exception):
474
"""Raised when media validation fails"""
475
476
class MultipartParseError(Exception):
477
"""Raised when multipart form parsing fails"""
478
```
479
480
## Types
481
482
```python { .api }
483
# Media handler base classes
484
BaseHandler: type
485
TextBaseHandlerWS: type
486
BinaryBaseHandlerWS: type
487
488
# Handler registry
489
Handlers: type
490
MissingDependencyHandler: type
491
492
# Built-in handlers
493
JSONHandler: type
494
JSONHandlerWS: type
495
MessagePackHandler: type
496
MessagePackHandlerWS: type
497
MultipartFormHandler: type
498
URLEncodedFormHandler: type
499
500
# Validation
501
falcon.media.validators.jsonschema.validate: callable
502
503
# Media errors
504
MediaNotFoundError: type
505
MediaMalformedError: type
506
MediaValidationError: type
507
MultipartParseError: type
508
```