|
8 | 8 | from typing import get_origin |
9 | 9 | from functools import wraps |
10 | 10 |
|
| 11 | +from flask import Response |
11 | 12 | from flask import jsonify |
12 | 13 | from flask import request |
13 | 14 | from flask import current_app |
|
20 | 21 | VALIDATE_PARAMS_MAX_DEPTH = 4 |
21 | 22 |
|
22 | 23 |
|
| 24 | +def _handle_bad_request( |
| 25 | + use_error_handlers: bool, |
| 26 | + message: str, |
| 27 | + solution: Optional[str] = None, |
| 28 | + status_code: int = 400, |
| 29 | + original_exception: Optional[Exception] = None, |
| 30 | +) -> Response: |
| 31 | + if use_error_handlers: |
| 32 | + raise BadRequestError(message, solution) from original_exception |
| 33 | + else: |
| 34 | + error_response = {"error": message} |
| 35 | + return make_response(jsonify(error_response), status_code) |
| 36 | + |
| 37 | + |
23 | 38 | def _is_optional(type_hint: Type) -> bool: # type: ignore |
24 | 39 | """Check if the type hint is :data:`~typing.Optional`. |
25 | 40 |
|
@@ -246,115 +261,45 @@ def example(): |
246 | 261 | def decorator(fn): # type: ignore |
247 | 262 | @wraps(fn) |
248 | 263 | def wrapper(*args, **kwargs): # type: ignore |
249 | | - use_error_handlers = False |
250 | | - if current_app.extensions.get("flask_utils") is not None: |
251 | | - if current_app.extensions["flask_utils"].has_error_handlers_registered: |
252 | | - use_error_handlers = True |
| 264 | + use_error_handlers = ( |
| 265 | + current_app.extensions.get("flask_utils") is not None |
| 266 | + and current_app.extensions["flask_utils"].has_error_handlers_registered |
| 267 | + ) |
253 | 268 |
|
254 | 269 | try: |
255 | 270 | data = request.get_json() |
256 | 271 | except BadRequest as e: |
257 | | - if use_error_handlers: |
258 | | - raise BadRequestError("The Json Body is malformed.") from e |
259 | | - else: |
260 | | - return make_response( |
261 | | - jsonify( |
262 | | - { |
263 | | - "error": "The Json Body is malformed.", |
264 | | - } |
265 | | - ), |
266 | | - 400, |
267 | | - ) |
| 272 | + return _handle_bad_request(use_error_handlers, "The Json Body is malformed.", original_exception=e) |
268 | 273 | except UnsupportedMediaType as e: |
269 | | - if use_error_handlers: |
270 | | - raise BadRequestError( |
271 | | - "The Content-Type header is missing or is not set to application/json, " |
272 | | - "or the JSON body is missing." |
273 | | - ) from e |
274 | | - else: |
275 | | - return make_response( |
276 | | - jsonify( |
277 | | - { |
278 | | - "error": "The Content-Type header is missing or is not set to application/json, " |
279 | | - "or the JSON body is missing.", |
280 | | - } |
281 | | - ), |
282 | | - 400, |
283 | | - ) |
| 274 | + return _handle_bad_request( |
| 275 | + use_error_handlers, |
| 276 | + "The Content-Type header is missing or is not set to application/json, " |
| 277 | + "or the JSON body is missing.", |
| 278 | + original_exception=e, |
| 279 | + ) |
284 | 280 |
|
285 | 281 | if not data: |
286 | | - if use_error_handlers: |
287 | | - raise BadRequestError("Missing json body.") |
288 | | - else: |
289 | | - return make_response( |
290 | | - jsonify( |
291 | | - { |
292 | | - "error": "Missing json body.", |
293 | | - } |
294 | | - ), |
295 | | - 400, |
296 | | - ) |
| 282 | + return _handle_bad_request(use_error_handlers, "Missing json body.") |
297 | 283 |
|
298 | 284 | if not isinstance(data, dict): |
299 | | - if use_error_handlers: |
300 | | - raise BadRequestError("JSON body must be a dict") |
301 | | - else: |
302 | | - return make_response( |
303 | | - jsonify( |
304 | | - { |
305 | | - "error": "JSON body must be a dict", |
306 | | - } |
307 | | - ), |
308 | | - 400, |
309 | | - ) |
| 285 | + return _handle_bad_request(use_error_handlers, "JSON body must be a dict") |
310 | 286 |
|
311 | 287 | for key, type_hint in parameters.items(): |
312 | 288 | if not _is_optional(type_hint) and key not in data: |
313 | | - if use_error_handlers: |
314 | | - raise BadRequestError(f"Missing key: {key}", f"Expected keys are: {parameters.keys()}") |
315 | | - else: |
316 | | - return make_response( |
317 | | - jsonify( |
318 | | - { |
319 | | - "error": f"Missing key: {key}", |
320 | | - "expected_keys": parameters.keys(), |
321 | | - } |
322 | | - ), |
323 | | - 400, |
324 | | - ) |
| 289 | + return _handle_bad_request( |
| 290 | + use_error_handlers, f"Missing key: {key}", f"Expected keys are: {parameters.keys()}" |
| 291 | + ) |
325 | 292 |
|
326 | 293 | for key in data: |
327 | 294 | if key not in parameters: |
328 | 295 | if use_error_handlers: |
329 | | - raise BadRequestError( |
330 | | - f"Unexpected key: {key}.", |
331 | | - f"Expected keys are: {parameters.keys()}", |
332 | | - ) |
333 | | - else: |
334 | | - return make_response( |
335 | | - jsonify( |
336 | | - { |
337 | | - "error": f"Unexpected key: {key}.", |
338 | | - "expected_keys": parameters.keys(), |
339 | | - } |
340 | | - ), |
341 | | - 400, |
342 | | - ) |
| 296 | + raise BadRequestError(f"Unexpected key: {key}.", f"Expected keys are: {parameters.keys()}") |
343 | 297 |
|
344 | 298 | for key in data: |
345 | 299 | if key in parameters and not _check_type(data[key], parameters[key], allow_empty): |
346 | | - if use_error_handlers: |
347 | | - raise BadRequestError(f"Wrong type for key {key}.", f"It should be {parameters[key]}") |
348 | | - else: |
349 | | - return make_response( |
350 | | - jsonify( |
351 | | - { |
352 | | - "error": f"Wrong type for key {key}.", |
353 | | - "expected_type": parameters[key], |
354 | | - } |
355 | | - ), |
356 | | - 400, |
357 | | - ) |
| 300 | + return _handle_bad_request( |
| 301 | + use_error_handlers, f"Wrong type for key {key}.", f"It should be {parameters[key]}" |
| 302 | + ) |
358 | 303 |
|
359 | 304 | return fn(*args, **kwargs) |
360 | 305 |
|
|
0 commit comments