2017-09-21 11:51:37 +00:00
|
|
|
"""OpenAPI core wrappers module"""
|
|
|
|
from six import iteritems
|
2017-09-25 11:22:55 +00:00
|
|
|
from six.moves.urllib.parse import urljoin
|
2017-09-21 11:51:37 +00:00
|
|
|
|
|
|
|
from openapi_core.exceptions import (
|
|
|
|
OpenAPIMappingError, MissingParameterError, InvalidContentTypeError,
|
2017-09-25 11:22:55 +00:00
|
|
|
InvalidServerError,
|
2017-09-21 11:51:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
SPEC_LOCATION_TO_REQUEST_LOCATION_MAPPING = {
|
|
|
|
'path': 'view_args',
|
|
|
|
'query': 'args',
|
|
|
|
'headers': 'headers',
|
|
|
|
'cookies': 'cookies',
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class RequestParameters(dict):
|
|
|
|
|
|
|
|
valid_locations = ['path', 'query', 'headers', 'cookies']
|
|
|
|
|
|
|
|
def __getitem__(self, location):
|
|
|
|
self.validate_location(location)
|
|
|
|
|
|
|
|
return self.setdefault(location, {})
|
|
|
|
|
|
|
|
def __setitem__(self, location, value):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def validate_location(cls, location):
|
|
|
|
if location not in cls.valid_locations:
|
|
|
|
raise OpenAPIMappingError(
|
|
|
|
"Unknown parameter location: {0}".format(str(location)))
|
|
|
|
|
|
|
|
|
2017-09-25 11:22:55 +00:00
|
|
|
class BaseRequestFactory(object):
|
|
|
|
|
|
|
|
def get_operation(self, request, spec):
|
|
|
|
server = self._get_server(request, spec)
|
|
|
|
|
|
|
|
operation_pattern = request.full_url_pattern.replace(
|
|
|
|
server.default_url, '')
|
2017-10-19 09:34:20 +00:00
|
|
|
method = request.method.lower()
|
2017-09-25 11:22:55 +00:00
|
|
|
|
2017-10-19 09:34:20 +00:00
|
|
|
return spec.get_operation(operation_pattern, method)
|
2017-09-25 11:22:55 +00:00
|
|
|
|
|
|
|
def _get_server(self, request, spec):
|
|
|
|
for server in spec.servers:
|
|
|
|
if server.default_url in request.full_url_pattern:
|
|
|
|
return server
|
|
|
|
|
|
|
|
raise InvalidServerError(
|
|
|
|
"Invalid request server {0}".format(request.full_url_pattern))
|
|
|
|
|
|
|
|
|
|
|
|
class RequestParametersFactory(BaseRequestFactory):
|
2017-09-21 11:51:37 +00:00
|
|
|
|
|
|
|
def __init__(self, attr_mapping=SPEC_LOCATION_TO_REQUEST_LOCATION_MAPPING):
|
|
|
|
self.attr_mapping = attr_mapping
|
|
|
|
|
|
|
|
def create(self, request, spec):
|
2017-09-25 11:22:55 +00:00
|
|
|
operation = self.get_operation(request, spec)
|
2017-09-21 11:51:37 +00:00
|
|
|
|
|
|
|
params = RequestParameters()
|
|
|
|
for param_name, param in iteritems(operation.parameters):
|
|
|
|
try:
|
2017-10-18 13:42:10 +00:00
|
|
|
raw_value = self._get_raw_value(request, param)
|
2017-09-21 11:51:37 +00:00
|
|
|
except MissingParameterError:
|
|
|
|
if param.required:
|
|
|
|
raise
|
2017-10-18 13:42:10 +00:00
|
|
|
|
|
|
|
if not param.schema or not param.schema.default:
|
|
|
|
continue
|
|
|
|
raw_value = param.schema.default
|
|
|
|
|
|
|
|
value = param.unmarshal(raw_value)
|
2017-09-21 11:51:37 +00:00
|
|
|
|
|
|
|
params[param.location][param_name] = value
|
|
|
|
return params
|
|
|
|
|
2017-10-18 13:42:10 +00:00
|
|
|
def _get_raw_value(self, request, param):
|
2017-09-21 11:51:37 +00:00
|
|
|
request_location = self.attr_mapping[param.location]
|
|
|
|
request_attr = getattr(request, request_location)
|
|
|
|
|
|
|
|
try:
|
2017-10-18 13:42:10 +00:00
|
|
|
return request_attr[param.name]
|
2017-09-21 11:51:37 +00:00
|
|
|
except KeyError:
|
|
|
|
raise MissingParameterError(
|
|
|
|
"Missing required `{0}` parameter".format(param.name))
|
|
|
|
|
|
|
|
|
2017-09-25 11:22:55 +00:00
|
|
|
class RequestBodyFactory(BaseRequestFactory):
|
2017-09-21 11:51:37 +00:00
|
|
|
|
|
|
|
def create(self, request, spec):
|
2017-09-25 11:22:55 +00:00
|
|
|
operation = self.get_operation(request, spec)
|
2017-09-21 11:51:37 +00:00
|
|
|
|
2017-09-25 13:20:23 +00:00
|
|
|
if operation.request_body is None:
|
|
|
|
return None
|
|
|
|
|
2017-09-21 11:51:37 +00:00
|
|
|
try:
|
2017-10-09 14:57:07 +00:00
|
|
|
media_type = operation.request_body[request.mimetype]
|
2017-09-21 11:51:37 +00:00
|
|
|
except KeyError:
|
|
|
|
raise InvalidContentTypeError(
|
2017-10-09 14:57:07 +00:00
|
|
|
"Invalid media type `{0}`".format(request.mimetype))
|
2017-09-21 11:51:37 +00:00
|
|
|
|
|
|
|
return media_type.unmarshal(request.data)
|
|
|
|
|
|
|
|
|
|
|
|
class BaseOpenAPIRequest(object):
|
|
|
|
|
2017-09-25 11:22:55 +00:00
|
|
|
host_url = NotImplemented
|
2017-09-21 11:51:37 +00:00
|
|
|
path = NotImplemented
|
|
|
|
path_pattern = NotImplemented
|
|
|
|
method = NotImplemented
|
|
|
|
|
|
|
|
args = NotImplemented
|
|
|
|
view_args = NotImplemented
|
|
|
|
headers = NotImplemented
|
|
|
|
cookies = NotImplemented
|
|
|
|
|
|
|
|
data = NotImplemented
|
|
|
|
|
2017-10-09 14:57:07 +00:00
|
|
|
mimetype = NotImplemented
|
2017-09-21 11:51:37 +00:00
|
|
|
|
2017-09-25 11:22:55 +00:00
|
|
|
@property
|
|
|
|
def full_url_pattern(self):
|
|
|
|
return urljoin(self.host_url, self.path_pattern)
|
|
|
|
|
2017-09-21 11:51:37 +00:00
|
|
|
def get_parameters(self, spec):
|
|
|
|
return RequestParametersFactory().create(self, spec)
|
|
|
|
|
|
|
|
def get_body(self, spec):
|
|
|
|
return RequestBodyFactory().create(self, spec)
|