This is an automated email from the ASF dual-hosted git repository.
ephraimanierobi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new e89a7eeea6 Use custom validator for OpenAPI request body (#30596)
e89a7eeea6 is described below
commit e89a7eeea6a7a5a5a30a3f3cf86dfabf7c343412
Author: Tzu-ping Chung <[email protected]>
AuthorDate: Wed Apr 12 20:40:05 2023 +0800
Use custom validator for OpenAPI request body (#30596)
* Use custom validator for OpenAPI request body
The default error message for an empty request body from Connexion
is quite unhelpful (taken directly from JSONSchema). This custom
validator emits a more helpful message for this particular context.
* Add test for custom request body validator
Co-Authored-By: maahir22 <[email protected]>
---------
Co-authored-by: maahir22 <[email protected]>
---
airflow/www/extensions/init_views.py | 17 +++++++++++++++++
.../endpoints/test_task_instance_endpoint.py | 8 ++++++++
2 files changed, 25 insertions(+)
diff --git a/airflow/www/extensions/init_views.py
b/airflow/www/extensions/init_views.py
index 41408942e4..d3dc3b7c62 100644
--- a/airflow/www/extensions/init_views.py
+++ b/airflow/www/extensions/init_views.py
@@ -21,6 +21,8 @@ import warnings
from os import path
from connexion import FlaskApi, ProblemException, Resolver
+from connexion.decorators.validation import RequestBodyValidator
+from connexion.exceptions import BadRequestProblem
from flask import Flask, request
from airflow.api_connexion.exceptions import common_error_handler
@@ -209,6 +211,20 @@ class _LazyResolver(Resolver):
return _LazyResolution(self.resolve_function_from_operation_id,
operation_id)
+class _CustomErrorRequestBodyValidator(RequestBodyValidator):
+ """Custom request body validator that overrides error messages.
+
+ By default, Connextion emits a very generic *None is not of type 'object'*
+ error when receiving an empty request body (with the view specifying the
+ body as non-nullable). We overrides it to provide a more useful message.
+ """
+
+ def validate_schema(self, data, url):
+ if not self.is_null_value_valid and data is None:
+ raise BadRequestProblem(detail="Request body must not be empty")
+ return super().validate_schema(data, url)
+
+
def init_api_connexion(app: Flask) -> None:
"""Initialize Stable API"""
base_path = "/api/v1"
@@ -245,6 +261,7 @@ def init_api_connexion(app: Flask) -> None:
},
strict_validation=True,
validate_responses=True,
+ validator_map={"body": _CustomErrorRequestBodyValidator},
).blueprint
api_bp.after_request(set_cors_headers_on_response)
diff --git a/tests/api_connexion/endpoints/test_task_instance_endpoint.py
b/tests/api_connexion/endpoints/test_task_instance_endpoint.py
index ac2b4b694d..9f1f74df55 100644
--- a/tests/api_connexion/endpoints/test_task_instance_endpoint.py
+++ b/tests/api_connexion/endpoints/test_task_instance_endpoint.py
@@ -875,6 +875,14 @@ class TestGetTaskInstancesBatch(TestTaskInstanceEndpoint):
)
assert response.status_code == 403
+ def test_should_raise_400_for_no_json(self):
+ response = self.client.post(
+ "/api/v1/dags/~/dagRuns/~/taskInstances/list",
+ environ_overrides={"REMOTE_USER": "test"},
+ )
+ assert response.status_code == 400
+ assert response.json["detail"] == "Request body must not be empty"
+
@pytest.mark.parametrize(
"payload, expected",
[