0
# Validation System
1
2
Automatic request and response validation based on OpenAPI schema definitions. Connexion provides comprehensive validation for various content types with customizable validation strategies.
3
4
## Capabilities
5
6
### Validator Mapping
7
8
Central registry of validators for different content types and validation scenarios.
9
10
```python { .api }
11
VALIDATOR_MAP: dict
12
"""
13
Global mapping of validation types to validator classes.
14
Keys include:
15
- 'body': Request body validators by content type
16
- 'parameter': Parameter validators
17
- 'response': Response validators by content type
18
"""
19
```
20
21
### Abstract Base Validators
22
23
Base classes for implementing custom validators.
24
25
```python { .api }
26
class AbstractRequestBodyValidator:
27
"""Base class for request body validators"""
28
29
def __init__(self, schema: dict, validator=None, **kwargs):
30
"""
31
Initialize request body validator.
32
33
Parameters:
34
- schema: JSON schema for validation
35
- validator: Custom validator instance
36
- **kwargs: Additional validator options
37
"""
38
39
def validate_schema(self, body, url: str) -> dict:
40
"""
41
Validate request body against schema.
42
43
Parameters:
44
- body: Request body to validate
45
- url: Request URL for error context
46
47
Returns:
48
dict: Validated and possibly transformed body
49
50
Raises:
51
BadRequestProblem: If validation fails
52
"""
53
54
@classmethod
55
def validate_formdata_parameter_list(cls, request_body: dict) -> dict:
56
"""
57
Validate form data parameters.
58
59
Parameters:
60
- request_body: Form data dictionary
61
62
Returns:
63
dict: Validated form data
64
"""
65
66
class AbstractParameterValidator:
67
"""Base class for parameter validators"""
68
69
def __init__(self, parameters: list, uri_parser=None, **kwargs):
70
"""
71
Initialize parameter validator.
72
73
Parameters:
74
- parameters: List of parameter definitions
75
- uri_parser: URI parsing utility
76
- **kwargs: Additional options
77
"""
78
79
def validate_query_parameter_list(self, request) -> dict:
80
"""
81
Validate query parameters.
82
83
Parameters:
84
- request: Request object
85
86
Returns:
87
dict: Validated query parameters
88
"""
89
90
def validate_path_parameter_list(self, request) -> dict:
91
"""
92
Validate path parameters.
93
94
Parameters:
95
- request: Request object
96
97
Returns:
98
dict: Validated path parameters
99
"""
100
101
def validate_header_parameter_list(self, request) -> dict:
102
"""
103
Validate header parameters.
104
105
Parameters:
106
- request: Request object
107
108
Returns:
109
dict: Validated header parameters
110
"""
111
112
class AbstractResponseBodyValidator:
113
"""Base class for response body validators"""
114
115
def __init__(self, schema: dict, validator=None, **kwargs):
116
"""
117
Initialize response body validator.
118
119
Parameters:
120
- schema: JSON schema for validation
121
- validator: Custom validator instance
122
- **kwargs: Additional options
123
"""
124
125
def validate_schema(self, data, url: str) -> dict:
126
"""
127
Validate response body against schema.
128
129
Parameters:
130
- data: Response data to validate
131
- url: Request URL for error context
132
133
Returns:
134
dict: Validated response data
135
136
Raises:
137
InternalServerError: If validation fails
138
"""
139
```
140
141
### Request Body Validators
142
143
Concrete validators for different request content types.
144
145
```python { .api }
146
class JSONRequestBodyValidator(AbstractRequestBodyValidator):
147
"""Validator for application/json request bodies"""
148
149
def validate_schema(self, body, url: str) -> dict:
150
"""Validate JSON request body against OpenAPI schema"""
151
152
class FormDataValidator(AbstractRequestBodyValidator):
153
"""Validator for application/x-www-form-urlencoded request bodies"""
154
155
def validate_schema(self, body, url: str) -> dict:
156
"""Validate form data against OpenAPI schema"""
157
158
class MultiPartFormDataValidator(AbstractRequestBodyValidator):
159
"""Validator for multipart/form-data request bodies"""
160
161
def validate_schema(self, body, url: str) -> dict:
162
"""Validate multipart form data including file uploads"""
163
```
164
165
### Parameter Validators
166
167
Validators for URL parameters, query strings, and headers.
168
169
```python { .api }
170
class ParameterValidator(AbstractParameterValidator):
171
"""Validator for URL path, query, and header parameters"""
172
173
def validate_query_parameter_list(self, request) -> dict:
174
"""
175
Validate query parameters against OpenAPI parameter definitions.
176
Handles type coercion, required parameter checking, and format validation.
177
"""
178
179
def validate_path_parameter_list(self, request) -> dict:
180
"""
181
Validate path parameters against OpenAPI parameter definitions.
182
Performs type conversion and validation.
183
"""
184
185
def validate_header_parameter_list(self, request) -> dict:
186
"""
187
Validate header parameters against OpenAPI parameter definitions.
188
Handles case-insensitive header names and type validation.
189
"""
190
```
191
192
### Response Validators
193
194
Validators for response data validation.
195
196
```python { .api }
197
class JSONResponseBodyValidator(AbstractResponseBodyValidator):
198
"""Validator for JSON response bodies"""
199
200
def validate_schema(self, data, url: str) -> dict:
201
"""
202
Validate JSON response data against OpenAPI response schema.
203
Ensures API responses match the specification.
204
"""
205
```
206
207
### Validation Configuration
208
209
Configuration options for validation behavior.
210
211
```python { .api }
212
class ValidationOptions:
213
"""Configuration for validation behavior"""
214
215
def __init__(
216
self,
217
strict_validation: bool = False,
218
validate_responses: bool = False,
219
pythonic_params: bool = False
220
):
221
"""
222
Initialize validation options.
223
224
Parameters:
225
- strict_validation: Enable strict validation mode
226
- validate_responses: Enable response validation
227
- pythonic_params: Convert parameter names to pythonic style
228
"""
229
```
230
231
## Usage Examples
232
233
### Custom Request Body Validator
234
235
```python
236
from connexion.validators import AbstractRequestBodyValidator
237
from connexion.exceptions import BadRequestProblem
238
239
class CustomJSONValidator(AbstractRequestBodyValidator):
240
"""Custom JSON validator with additional business rules"""
241
242
def validate_schema(self, body, url):
243
# First run standard JSON schema validation
244
validated_body = super().validate_schema(body, url)
245
246
# Add custom validation rules
247
if 'email' in validated_body:
248
email = validated_body['email']
249
if not self.is_valid_email(email):
250
raise BadRequestProblem(
251
detail=f"Invalid email format: {email}"
252
)
253
254
# Check for business rule violations
255
if validated_body.get('age', 0) < 0:
256
raise BadRequestProblem(
257
detail="Age cannot be negative"
258
)
259
260
return validated_body
261
262
def is_valid_email(self, email):
263
# Custom email validation logic
264
return '@' in email and '.' in email
265
266
# Register custom validator
267
from connexion.validators import VALIDATOR_MAP
268
VALIDATOR_MAP['body']['application/json'] = CustomJSONValidator
269
```
270
271
### Custom Parameter Validator
272
273
```python
274
from connexion.validators import AbstractParameterValidator
275
from connexion.exceptions import BadRequestProblem
276
277
class EnhancedParameterValidator(AbstractParameterValidator):
278
"""Parameter validator with enhanced type coercion"""
279
280
def validate_query_parameter_list(self, request):
281
validated_params = super().validate_query_parameter_list(request)
282
283
# Custom parameter processing
284
if 'date_range' in validated_params:
285
date_range = validated_params['date_range']
286
try:
287
start, end = date_range.split(',')
288
validated_params['start_date'] = datetime.fromisoformat(start)
289
validated_params['end_date'] = datetime.fromisoformat(end)
290
del validated_params['date_range']
291
except ValueError:
292
raise BadRequestProblem(
293
detail="Invalid date range format. Use: YYYY-MM-DD,YYYY-MM-DD"
294
)
295
296
return validated_params
297
298
# Use custom validator
299
app.add_api(
300
'api.yaml',
301
validator_map={
302
'parameter': EnhancedParameterValidator
303
}
304
)
305
```
306
307
### Response Validation
308
309
```python
310
from connexion import AsyncApp
311
312
# Enable response validation
313
app = AsyncApp(__name__, validate_responses=True)
314
app.add_api('api.yaml')
315
316
# Responses that don't match the OpenAPI schema will raise errors
317
def get_user(user_id):
318
# This response must match the OpenAPI response schema
319
return {
320
"id": user_id,
321
"name": "John Doe",
322
"email": "john@example.com"
323
}
324
```
325
326
### Validation Error Handling
327
328
```python
329
from connexion.exceptions import BadRequestProblem, ValidationError
330
331
def custom_validation_error_handler(exception):
332
"""Handle validation errors with custom responses"""
333
334
if isinstance(exception, ValidationError):
335
return {
336
"error": "Validation failed",
337
"details": str(exception),
338
"field": getattr(exception, 'field', None)
339
}, 400
340
341
return {"error": "Bad request"}, 400
342
343
app.add_error_handler(ValidationError, custom_validation_error_handler)
344
```
345
346
### Strict Validation Mode
347
348
```python
349
# Enable strict validation for all APIs
350
app = AsyncApp(__name__, strict_validation=True)
351
352
# Or per API
353
app.add_api('api.yaml', strict_validation=True)
354
355
# Strict mode enforces:
356
# - All required parameters must be present
357
# - No additional properties in request bodies (if additionalProperties: false)
358
# - Exact type matching
359
# - Format validation (email, date, etc.)
360
```
361
362
### Pythonic Parameter Names
363
364
```python
365
# Enable pythonic parameter conversion
366
app = AsyncApp(__name__, pythonic_params=True)
367
368
# OpenAPI parameter: user-id becomes user_id in Python function
369
def get_user(user_id: int): # Maps from user-id parameter
370
return {"user_id": user_id}
371
372
# Query parameter: max-results becomes max_results
373
def search_users(max_results: int = 10):
374
return {"results": [], "limit": max_results}
375
```
376
377
### File Upload Validation
378
379
```python
380
from connexion.validators import MultiPartFormDataValidator
381
382
def upload_avatar():
383
# Validation automatically handles:
384
# - File size limits (if specified in OpenAPI)
385
# - Content type validation
386
# - Required file fields
387
388
file = request.files['avatar']
389
390
# Additional custom validation
391
if file.content_type not in ['image/jpeg', 'image/png']:
392
raise BadRequestProblem(
393
detail="Only JPEG and PNG images allowed"
394
)
395
396
if len(file.read()) > 5 * 1024 * 1024: # 5MB limit
397
raise BadRequestProblem(
398
detail="File size must be less than 5MB"
399
)
400
401
# Process file...
402
return {"status": "uploaded"}, 201
403
```
404
405
### Custom Validator Integration
406
407
```python
408
from connexion.validators import VALIDATOR_MAP
409
410
# Register custom validators globally
411
VALIDATOR_MAP['body']['application/xml'] = XMLValidator
412
VALIDATOR_MAP['body']['text/csv'] = CSVValidator
413
VALIDATOR_MAP['parameter'] = CustomParameterValidator
414
415
# Or use per-API validator mapping
416
custom_validators = {
417
'body': {
418
'application/json': CustomJSONValidator,
419
'multipart/form-data': CustomMultipartValidator
420
},
421
'parameter': EnhancedParameterValidator,
422
'response': {
423
'application/json': StrictJSONResponseValidator
424
}
425
}
426
427
app.add_api('api.yaml', validator_map=custom_validators)
428
```