Skip to content

Commit

Permalink
openapi: remove body preprocessing
Browse files Browse the repository at this point in the history
Body is already validated using jsonschema. There was also some type
casting but it was wrong: e.g. not recurring deeply into dicts and lists,
relying on existence of "type" in schema (which is not there e.g. if
oneOf is used). Anyway, the only reason why types should be casted is
converting integer values to float if the type is number. But this is in
most cases irrelevant.

Added an example, which did not work before this commit (echoed `{}`)
e.g. for
```
curl localhost:8080/api/foo -H 'content-type: application/json' -d
'{"foo": 1}'
```
but now the example works (echoes `{"foo": 1}`).
  • Loading branch information
p4l1ly committed Apr 9, 2022
1 parent ea45242 commit 8fe35a3
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 10 deletions.
26 changes: 16 additions & 10 deletions connexion/operations/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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:
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):
if x_body_name in arguments or has_kwargs:
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
Expand All @@ -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 {})

Expand Down
20 changes: 20 additions & 0 deletions examples/openapi3/oneof/oneof.py
Original file line number Diff line number Diff line change
@@ -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()
32 changes: 32 additions & 0 deletions examples/openapi3/oneof/schema.yaml
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit 8fe35a3

Please sign in to comment.