mirror of
https://github.com/correl/openapi-core.git
synced 2024-12-29 11:09:25 +00:00
Response JSON text as array fix
This commit is contained in:
parent
4fc02af09c
commit
0350562b54
5 changed files with 92 additions and 4 deletions
|
@ -1,9 +1,17 @@
|
||||||
"""OpenAPI core mediaTypes module"""
|
"""OpenAPI core mediaTypes module"""
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from json import loads
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
from openapi_core.exceptions import InvalidValueType, InvalidMediaTypeValue
|
from openapi_core.exceptions import InvalidValueType, InvalidMediaTypeValue
|
||||||
|
|
||||||
|
|
||||||
|
MEDIA_TYPE_DESERIALIZERS = {
|
||||||
|
'application/json': loads,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class MediaType(object):
|
class MediaType(object):
|
||||||
"""Represents an OpenAPI MediaType."""
|
"""Represents an OpenAPI MediaType."""
|
||||||
|
|
||||||
|
@ -11,12 +19,29 @@ class MediaType(object):
|
||||||
self.mimetype = mimetype
|
self.mimetype = mimetype
|
||||||
self.schema = schema
|
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):
|
def unmarshal(self, value):
|
||||||
if not self.schema:
|
if not self.schema:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
try:
|
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:
|
except InvalidValueType as exc:
|
||||||
raise InvalidMediaTypeValue(str(exc))
|
raise InvalidMediaTypeValue(str(exc))
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import warnings
|
||||||
from distutils.util import strtobool
|
from distutils.util import strtobool
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
|
||||||
from json import loads
|
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
from openapi_core.enums import SchemaType, SchemaFormat
|
from openapi_core.enums import SchemaType, SchemaFormat
|
||||||
|
@ -126,8 +125,8 @@ class Schema(object):
|
||||||
return list(map(self.items.unmarshal, value))
|
return list(map(self.items.unmarshal, value))
|
||||||
|
|
||||||
def _unmarshal_object(self, value):
|
def _unmarshal_object(self, value):
|
||||||
if isinstance(value, (str, bytes)):
|
if not isinstance(value, (dict, )):
|
||||||
value = loads(value)
|
raise InvalidValueType("Value of {0} not an object".format(value))
|
||||||
|
|
||||||
all_properties = self.get_all_properties()
|
all_properties = self.get_all_properties()
|
||||||
all_required_properties = self.get_all_required_properties()
|
all_required_properties = self.get_all_required_properties()
|
||||||
|
|
|
@ -108,6 +108,21 @@ paths:
|
||||||
$ref: "#/components/schemas/PetData"
|
$ref: "#/components/schemas/PetData"
|
||||||
default:
|
default:
|
||||||
$ref: "#/components/responses/ErrorResponse"
|
$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:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
Address:
|
Address:
|
||||||
|
@ -186,6 +201,10 @@ components:
|
||||||
properties:
|
properties:
|
||||||
data:
|
data:
|
||||||
$ref: "#/components/schemas/Pet"
|
$ref: "#/components/schemas/Pet"
|
||||||
|
TagList:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Tag"
|
||||||
Error:
|
Error:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
|
|
@ -655,3 +655,27 @@ class TestPetstore(object):
|
||||||
|
|
||||||
assert response_result.errors == []
|
assert response_result.errors == []
|
||||||
assert response_result.data == data_json
|
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
|
||||||
|
|
|
@ -4,6 +4,7 @@ import pytest
|
||||||
from openapi_core.exceptions import (
|
from openapi_core.exceptions import (
|
||||||
InvalidServer, InvalidOperation, MissingParameter,
|
InvalidServer, InvalidOperation, MissingParameter,
|
||||||
MissingBody, InvalidContentType, InvalidResponse, InvalidMediaTypeValue,
|
MissingBody, InvalidContentType, InvalidResponse, InvalidMediaTypeValue,
|
||||||
|
InvalidValue,
|
||||||
)
|
)
|
||||||
from openapi_core.shortcuts import create_spec
|
from openapi_core.shortcuts import create_spec
|
||||||
from openapi_core.validators import RequestValidator, ResponseValidator
|
from openapi_core.validators import RequestValidator, ResponseValidator
|
||||||
|
@ -239,6 +240,26 @@ class TestResponseValidator(object):
|
||||||
assert result.data is None
|
assert result.data is None
|
||||||
assert result.headers == {}
|
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):
|
def test_get_pets(self, validator):
|
||||||
request = MockRequest(self.host_url, 'get', '/v1/pets')
|
request = MockRequest(self.host_url, 'get', '/v1/pets')
|
||||||
response_json = {
|
response_json = {
|
||||||
|
|
Loading…
Reference in a new issue