Skip to content

Response JSON text as array fix #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion openapi_core/media_types.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,47 @@
"""OpenAPI core mediaTypes module"""
from collections import defaultdict

from json import loads
from six import iteritems

from openapi_core.exceptions import InvalidValueType, InvalidMediaTypeValue


MEDIA_TYPE_DESERIALIZERS = {
'application/json': loads,
}


class MediaType(object):
"""Represents an OpenAPI MediaType."""

def __init__(self, mimetype, schema=None):
self.mimetype = mimetype
self.schema = schema

def get_deserializer_mapping(self):
mapping = MEDIA_TYPE_DESERIALIZERS.copy()
return defaultdict(lambda: lambda x: x, mapping)

def get_dererializer(self):
mapping = self.get_deserializer_mapping()
return mapping[self.mimetype]

def deserialize(self, value):
deserializer = self.get_dererializer()
return deserializer(value)

def unmarshal(self, value):
if not self.schema:
return value

try:
return self.schema.unmarshal(value)
deserialized = self.deserialize(value)
except ValueError as exc:
raise InvalidMediaTypeValue(str(exc))

try:
return self.schema.unmarshal(deserialized)
except InvalidValueType as exc:
raise InvalidMediaTypeValue(str(exc))

Expand Down
5 changes: 2 additions & 3 deletions openapi_core/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from distutils.util import strtobool
from functools import lru_cache

from json import loads
from six import iteritems

from openapi_core.enums import SchemaType, SchemaFormat
Expand Down Expand Up @@ -126,8 +125,8 @@ def _unmarshal_collection(self, value):
return list(map(self.items.unmarshal, value))

def _unmarshal_object(self, value):
if isinstance(value, (str, bytes)):
value = loads(value)
if not isinstance(value, (dict, )):
raise InvalidValueType("Value of {0} not an object".format(value))

all_properties = self.get_all_properties()
all_required_properties = self.get_all_required_properties()
Expand Down
19 changes: 19 additions & 0 deletions tests/integration/data/v3.0/petstore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,21 @@ paths:
$ref: "#/components/schemas/PetData"
default:
$ref: "#/components/responses/ErrorResponse"
/tags:
get:
summary: List all tags
operationId: listTags
tags:
- tags
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/TagList"
default:
$ref: "#/components/responses/ErrorResponse"
components:
schemas:
Address:
Expand Down Expand Up @@ -186,6 +201,10 @@ components:
properties:
data:
$ref: "#/components/schemas/Pet"
TagList:
type: array
items:
$ref: "#/components/schemas/Tag"
Error:
type: object
required:
Expand Down
24 changes: 24 additions & 0 deletions tests/integration/test_petstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,3 +655,27 @@ def test_get_pet_not_found(self, spec, response_validator):

assert response_result.errors == []
assert response_result.data == data_json

def test_get_tags(self, spec, response_validator):
host_url = 'http://petstore.swagger.io/v1'
path_pattern = '/v1/tags'

request = MockRequest(
host_url, 'GET', '/tags',
path_pattern=path_pattern,
)

parameters = request.get_parameters(spec)
body = request.get_body(spec)

assert parameters == {}
assert body is None

data_json = []
data = json.dumps(data_json)
response = MockResponse(data)

response_result = response_validator.validate(request, response)

assert response_result.errors == []
assert response_result.data == data_json
21 changes: 21 additions & 0 deletions tests/integration/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from openapi_core.exceptions import (
InvalidServer, InvalidOperation, MissingParameter,
MissingBody, InvalidContentType, InvalidResponse, InvalidMediaTypeValue,
InvalidValue,
)
from openapi_core.shortcuts import create_spec
from openapi_core.validators import RequestValidator, ResponseValidator
Expand Down Expand Up @@ -239,6 +240,26 @@ def test_invalid_media_type_value(self, validator):
assert result.data is None
assert result.headers == {}

def test_invalid_value(self, validator):
request = MockRequest(self.host_url, 'get', '/v1/tags')
response_json = {
'data': [
{
'id': 1,
'name': 'Sparky'
},
],
}
response_data = json.dumps(response_json)
response = MockResponse(response_data)

result = validator.validate(request, response)

assert len(result.errors) == 1
assert type(result.errors[0]) == InvalidValue
assert result.data is None
assert result.headers == {}

def test_get_pets(self, validator):
request = MockRequest(self.host_url, 'get', '/v1/pets')
response_json = {
Expand Down