diff --git a/connexion/operations/openapi.py b/connexion/operations/openapi.py index 7f5d0de3a..176eb9669 100644 --- a/connexion/operations/openapi.py +++ b/connexion/operations/openapi.py @@ -9,6 +9,7 @@ from connexion.operations.abstract import AbstractOperation from ..decorators.uri_parsing import OpenAPIURIParser +from ..http_facts import FORM_CONTENT_TYPES from ..utils import deep_get, deep_merge, is_null, is_nullable, make_type logger = logging.getLogger("connexion.operations.openapi3") @@ -286,13 +287,28 @@ def _get_body_argument(self, body, arguments, has_kwargs, sanitize): 'the requestBody instead.', DeprecationWarning) x_body_name = sanitize(self.body_schema.get('x-body-name', 'body')) + if self.consumes[0] in FORM_CONTENT_TYPES: + result = self._get_body_argument_form(body) + else: + result = self._get_body_argument_json(body) + + if x_body_name in arguments or has_kwargs: + return {x_body_name: result} + return {} + + def _get_body_argument_json(self, body): # if the body came in null, and the schema says it can be null, we decide # to include no value for the body argument, rather than the default body if is_nullable(self.body_schema) and is_null(body): - if x_body_name in arguments or has_kwargs: - return {x_body_name: None} - return {} + return None + + if body is None: + default_body = self.body_schema.get('default', {}) + return deepcopy(default_body) + return body + + def _get_body_argument_form(self, body): # now determine the actual value for the body (whether it came in or is default) default_body = self.body_schema.get('default', {}) body_props = {k: {"schema": v} for k, v @@ -302,25 +318,11 @@ def _get_body_argument(self, body, arguments, has_kwargs, sanitize): # see: https://github.com/OAI/OpenAPI-Specification/blame/3.0.2/versions/3.0.2.md#L2305 additional_props = self.body_schema.get("additionalProperties", True) - if body is None: - body = deepcopy(default_body) - - # if the body isn't even an object, then none of the concerns below matter - if self.body_schema.get("type") != "object": - if x_body_name in arguments or has_kwargs: - return {x_body_name: body} - return {} - - # supply the initial defaults and convert all values to the proper types by schema body_arg = deepcopy(default_body) body_arg.update(body or {}) - res = {} if body_props or additional_props: - res = self._get_typed_body_values(body_arg, body_props, additional_props) - - if x_body_name in arguments or has_kwargs: - return {x_body_name: res} + return self._get_typed_body_values(body_arg, body_props, additional_props) return {} def _get_typed_body_values(self, body_arg, body_props, additional_props): diff --git a/tests/api/test_responses.py b/tests/api/test_responses.py index e5a6f38be..da76bbfba 100644 --- a/tests/api/test_responses.py +++ b/tests/api/test_responses.py @@ -388,3 +388,34 @@ def test_streaming_response(simple_app): app_client = simple_app.app.test_client() resp = app_client.get('/v1.0/get_streaming_response') assert resp.status_code == 200 + + +def test_oneof(simple_openapi_app): + app_client = simple_openapi_app.app.test_client() + + post_greeting = app_client.post( # type: flask.Response + '/v1.0/oneof_greeting', + data=json.dumps({"name": 3}), + content_type="application/json" + ) + assert post_greeting.status_code == 200 + assert post_greeting.content_type == 'application/json' + greeting_reponse = json.loads(post_greeting.data.decode('utf-8', 'replace')) + assert greeting_reponse['greeting'] == 'Hello 3' + + post_greeting = app_client.post( # type: flask.Response + '/v1.0/oneof_greeting', + data=json.dumps({"name": True}), + content_type="application/json" + ) + assert post_greeting.status_code == 200 + assert post_greeting.content_type == 'application/json' + greeting_reponse = json.loads(post_greeting.data.decode('utf-8', 'replace')) + assert greeting_reponse['greeting'] == 'Hello True' + + post_greeting = app_client.post( # type: flask.Response + '/v1.0/oneof_greeting', + data=json.dumps({"name": "jsantos"}), + content_type="application/json" + ) + assert post_greeting.status_code == 400 diff --git a/tests/fixtures/simple/openapi.yaml b/tests/fixtures/simple/openapi.yaml index 749abcb3f..9ab6f6915 100644 --- a/tests/fixtures/simple/openapi.yaml +++ b/tests/fixtures/simple/openapi.yaml @@ -1222,6 +1222,23 @@ paths: schema: type: string format: binary + /oneof_greeting: + post: + operationId: fakeapi.hello.post_greeting3 + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + oneOf: + - {type: boolean} + - {type: number} + additionalProperties: false + responses: + '200': + description: Echo the validated request. servers: - url: http://localhost:{port}/{basePath}