args_parsing.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. from flask import jsonify
  2. from flexmeasures.data.schemas.utils import FMValidationError
  3. from webargs.multidictproxy import MultiDictProxy
  4. from webargs import ValidationError
  5. from webargs.flaskparser import parser
  6. """
  7. Utils for argument parsing (we use webargs),
  8. including error handling.
  9. """
  10. @parser.error_handler
  11. def handle_error(error, req, schema, *, error_status_code, error_headers):
  12. """Replacing webargs's error parser, so we can throw custom Exceptions."""
  13. if error.__class__ == ValidationError:
  14. # re-package all marshmallow's validation errors as our own kind (see below)
  15. raise FMValidationError(message=error.messages)
  16. raise error
  17. def validation_error_handler(error: FMValidationError):
  18. """Handles errors during parsing.
  19. Aborts the current HTTP request and responds with a 422 error.
  20. FMValidationError attributes "result" and "status" are packaged in the response.
  21. """
  22. status_code = 422
  23. response_data = dict(message=error.messages)
  24. if hasattr(error, "result"):
  25. response_data["result"] = error.result
  26. if hasattr(error, "status"):
  27. response_data["status"] = error.status
  28. response = jsonify(response_data)
  29. response.status_code = status_code
  30. return response
  31. @parser.location_loader("args_and_json")
  32. def load_data(request, schema):
  33. """
  34. We allow parameters to come from either GET args or POST JSON,
  35. as validators can be attached to either.
  36. """
  37. newdata = request.args.copy()
  38. if request.mimetype == "application/json" and request.method == "POST":
  39. newdata.update(request.get_json())
  40. return MultiDictProxy(newdata, schema)