diff --git a/connexion/operations/openapi.py b/connexion/operations/openapi.py index 7f5d0de3a..c6ee678a1 100644 --- a/connexion/operations/openapi.py +++ b/connexion/operations/openapi.py @@ -10,6 +10,7 @@ from ..decorators.uri_parsing import OpenAPIURIParser from ..utils import deep_get, deep_merge, is_null, is_nullable, make_type +from ..http_facts import FORM_CONTENT_TYPES logger = logging.getLogger("connexion.operations.openapi3") @@ -286,6 +287,12 @@ 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: + return self._get_body_argument_form(x_body_name, body, arguments, has_kwargs, sanitize) + else: + return self._get_body_argument_json(x_body_name, body, arguments, has_kwargs, sanitize) + + def _get_body_argument_json(self, x_body_name, body, arguments, has_kwargs, sanitize): # 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): @@ -293,6 +300,15 @@ def _get_body_argument(self, body, arguments, has_kwargs, sanitize): return {x_body_name: None} return {} + if body is None: + default_body = self.body_schema.get('default', {}) + body = deepcopy(default_body) + + if x_body_name in arguments or has_kwargs: + return {x_body_name: body} + return {} + + def _get_body_argument_form(self, x_body_name, body, arguments, has_kwargs, sanitize): # 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,16 +318,6 @@ 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 {}) diff --git a/examples/openapi3/oneof/oneof.py b/examples/openapi3/oneof/oneof.py new file mode 100644 index 000000000..03dd4e0e3 --- /dev/null +++ b/examples/openapi3/oneof/oneof.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import connexion +import jsonschema +import six +from connexion.decorators.validation import RequestBodyValidator +from connexion.json_schema import Draft4RequestValidator + +async def echo(body): + return body + +if __name__ == '__main__': + app = connexion.AioHttpApp( + __name__, + port=8080, + specification_dir='.', + options={'swagger_ui': True} + ) + app.add_api('schema.yaml') + app.run() diff --git a/examples/openapi3/oneof/schema.yaml b/examples/openapi3/oneof/schema.yaml new file mode 100644 index 000000000..9ab9937ea --- /dev/null +++ b/examples/openapi3/oneof/schema.yaml @@ -0,0 +1,32 @@ +openapi: '3.0.0' +info: + version: '1' + title: Custom Validator Example +servers: + - url: http://localhost:8080/{basePath} + variables: + basePath: + default: api +paths: + /echo: + post: + operationId: oneof.echo + requestBody: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + required: + - foo + properties: + foo: + oneOf: + - {type: boolean} + - {type: number} + default: + foo: false + responses: + '200': + description: Echo the validated request.