Skip to content

request and response protocols #407

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
Sep 4, 2022
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
9 changes: 2 additions & 7 deletions openapi_core/contrib/django/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
"""OpenAPI core contrib django module"""
from openapi_core.contrib.django.requests import DjangoOpenAPIRequestFactory
from openapi_core.contrib.django.responses import DjangoOpenAPIResponseFactory

DjangoOpenAPIRequest = DjangoOpenAPIRequestFactory().create
DjangoOpenAPIResponse = DjangoOpenAPIResponseFactory().create
from openapi_core.contrib.django.requests import DjangoOpenAPIRequest
from openapi_core.contrib.django.responses import DjangoOpenAPIResponse

__all__ = [
"DjangoOpenAPIRequestFactory",
"DjangoOpenAPIResponseFactory",
"DjangoOpenAPIRequest",
"DjangoOpenAPIResponse",
]
12 changes: 6 additions & 6 deletions openapi_core/contrib/django/middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
from django.core.exceptions import ImproperlyConfigured

from openapi_core.contrib.django.handlers import DjangoOpenAPIErrorsHandler
from openapi_core.contrib.django.requests import DjangoOpenAPIRequestFactory
from openapi_core.contrib.django.responses import DjangoOpenAPIResponseFactory
from openapi_core.contrib.django.requests import DjangoOpenAPIRequest
from openapi_core.contrib.django.responses import DjangoOpenAPIResponse
from openapi_core.validation.processors import OpenAPIProcessor
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.validation.response.validators import ResponseValidator


class DjangoOpenAPIMiddleware:

request_factory = DjangoOpenAPIRequestFactory()
response_factory = DjangoOpenAPIResponseFactory()
request_class = DjangoOpenAPIRequest
response_class = DjangoOpenAPIResponse
errors_handler = DjangoOpenAPIErrorsHandler()

def __init__(self, get_response):
Expand Down Expand Up @@ -53,7 +53,7 @@ def _handle_response_errors(self, response_result, req, resp):
return self.errors_handler.handle(response_result.errors, req, resp)

def _get_openapi_request(self, request):
return self.request_factory.create(request)
return self.request_class(request)

def _get_openapi_response(self, response):
return self.response_factory.create(response)
return self.response_class(response)
93 changes: 42 additions & 51 deletions openapi_core/contrib/django/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from werkzeug.datastructures import Headers
from werkzeug.datastructures import ImmutableMultiDict

from openapi_core.validation.request.datatypes import OpenAPIRequest
from openapi_core.validation.request.datatypes import RequestParameters

# https://docs.djangoproject.com/en/2.2/topics/http/urls/
Expand All @@ -21,59 +20,51 @@
PATH_PARAMETER_PATTERN = r"(?:[^\/]*?)<(?:(?:.*?:))*?(\w+)>(?:[^\/]*)"


class DjangoOpenAPIRequestFactory:
class DjangoOpenAPIRequest:

path_regex = re.compile(PATH_PARAMETER_PATTERN)

def create(self, request):
return OpenAPIRequest(
full_url_pattern=self._get_full_url_pattern(request),
method=self._get_method(request),
parameters=self._get_parameters(request),
body=self._get_body(request),
mimetype=self._get_mimetype(request),
)
def __init__(self, request):
self.request = request

def _get_parameters(self, request):
return RequestParameters(
path=self._get_path(request),
query=self._get_query(request),
header=self._get_header(request),
cookie=self._get_cookie(request),
self.parameters = RequestParameters(
path=self.request.resolver_match
and self.request.resolver_match.kwargs
or {},
query=ImmutableMultiDict(self.request.GET),
header=Headers(self.request.headers.items()),
cookie=ImmutableMultiDict(dict(self.request.COOKIES)),
)

def _get_path(self, request):
return request.resolver_match and request.resolver_match.kwargs or {}

def _get_query(self, request):
return ImmutableMultiDict(request.GET)

def _get_header(self, request):
return Headers(request.headers.items())

def _get_cookie(self, request):
return ImmutableMultiDict(dict(request.COOKIES))

def _get_full_url_pattern(self, request):
if request.resolver_match is None:
path_pattern = request.path
else:
route = self.path_regex.sub(r"{\1}", request.resolver_match.route)
# Delete start and end marker to allow concatenation.
if route[:1] == "^":
route = route[1:]
if route[-1:] == "$":
route = route[:-1]
path_pattern = "/" + route

current_scheme_host = request._current_scheme_host
return urljoin(current_scheme_host, path_pattern)

def _get_method(self, request):
return request.method.lower()

def _get_body(self, request):
return request.body

def _get_mimetype(self, request):
return request.content_type
@property
def host_url(self):
return self.request._current_scheme_host

@property
def path(self):
return self.request.path

@property
def path_pattern(self):
if self.request.resolver_match is None:
return None

route = self.path_regex.sub(r"{\1}", self.request.resolver_match.route)
# Delete start and end marker to allow concatenation.
if route[:1] == "^":
route = route[1:]
if route[-1:] == "$":
route = route[:-1]
return "/" + route

@property
def method(self):
return self.request.method.lower()

@property
def body(self):
return self.request.body

@property
def mimetype(self):
return self.request.content_type
33 changes: 15 additions & 18 deletions openapi_core/contrib/django/responses.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
"""OpenAPI core contrib django responses module"""
from werkzeug.datastructures import Headers

from openapi_core.validation.response.datatypes import OpenAPIResponse

class DjangoOpenAPIResponse:
def __init__(self, response):
self.response = response

class DjangoOpenAPIResponseFactory:
def create(self, response):
return OpenAPIResponse(
data=self._get_data(response),
status_code=self._get_status_code(response),
headers=self._get_header(response),
mimetype=self._get_mimetype(response),
)
@property
def data(self):
return self.response.content

def _get_data(self, response):
return response.content
@property
def status_code(self):
return self.response.status_code

def _get_status_code(self, response):
return response.status_code
@property
def headers(self):
return Headers(self.response.headers.items())

def _get_header(self, response):
return Headers(response.headers.items())

def _get_mimetype(self, response):
return response["Content-Type"]
@property
def mimetype(self):
return self.response["Content-Type"]
9 changes: 6 additions & 3 deletions openapi_core/contrib/falcon/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from openapi_core.contrib.falcon.requests import FalconOpenAPIRequestFactory
from openapi_core.contrib.falcon.responses import FalconOpenAPIResponseFactory
from openapi_core.contrib.falcon.requests import FalconOpenAPIRequest
from openapi_core.contrib.falcon.responses import FalconOpenAPIResponse

__all__ = ["FalconOpenAPIRequestFactory", "FalconOpenAPIResponseFactory"]
__all__ = [
"FalconOpenAPIRequest",
"FalconOpenAPIResponse",
]
28 changes: 14 additions & 14 deletions openapi_core/contrib/falcon/middlewares.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
"""OpenAPI core contrib falcon middlewares module"""

from openapi_core.contrib.falcon.handlers import FalconOpenAPIErrorsHandler
from openapi_core.contrib.falcon.requests import FalconOpenAPIRequestFactory
from openapi_core.contrib.falcon.responses import FalconOpenAPIResponseFactory
from openapi_core.contrib.falcon.requests import FalconOpenAPIRequest
from openapi_core.contrib.falcon.responses import FalconOpenAPIResponse
from openapi_core.validation.processors import OpenAPIProcessor
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.validation.response.validators import ResponseValidator


class FalconOpenAPIMiddleware:

request_factory = FalconOpenAPIRequestFactory()
response_factory = FalconOpenAPIResponseFactory()
request_class = FalconOpenAPIRequest
response_class = FalconOpenAPIResponse
errors_handler = FalconOpenAPIErrorsHandler()

def __init__(
self,
validation_processor,
request_factory=None,
response_factory=None,
request_class=None,
response_class=None,
errors_handler=None,
):
self.validation_processor = validation_processor
self.request_factory = request_factory or self.request_factory
self.response_factory = response_factory or self.response_factory
self.request_class = request_class or self.request_class
self.response_class = response_class or self.response_class
self.errors_handler = errors_handler or self.errors_handler

@classmethod
def from_spec(
cls,
spec,
request_factory=None,
response_factory=None,
request_class=None,
response_class=None,
errors_handler=None,
):
request_validator = RequestValidator(spec)
Expand All @@ -41,8 +41,8 @@ def from_spec(
)
return cls(
validation_processor,
request_factory=request_factory,
response_factory=response_factory,
request_class=request_class,
response_class=response_class,
errors_handler=errors_handler,
)

Expand Down Expand Up @@ -70,10 +70,10 @@ def _handle_response_errors(self, req, resp, response_result):
return self.errors_handler.handle(req, resp, response_result.errors)

def _get_openapi_request(self, request):
return self.request_factory.create(request)
return self.request_class(request)

def _get_openapi_response(self, response):
return self.response_factory.create(response)
return self.response_class(response)

def _process_openapi_request(self, openapi_request):
return self.validation_processor.process_request(openapi_request)
Expand Down
60 changes: 31 additions & 29 deletions openapi_core/contrib/falcon/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,45 @@
from werkzeug.datastructures import Headers
from werkzeug.datastructures import ImmutableMultiDict

from openapi_core.validation.request.datatypes import OpenAPIRequest
from openapi_core.validation.request.datatypes import RequestParameters


class FalconOpenAPIRequestFactory:
def __init__(self, default_when_empty=None):
class FalconOpenAPIRequest:
def __init__(self, request, default_when_empty=None):
self.request = request
if default_when_empty is None:
default_when_empty = {}
self.default_when_empty = default_when_empty

def create(self, request):
"""
Create OpenAPIRequest from falcon Request and route params.
"""
method = request.method.lower()
# Path gets deduced by path finder against spec
self.parameters = RequestParameters(
query=ImmutableMultiDict(list(self.request.params.items())),
header=Headers(self.request.headers),
cookie=self.request.cookies,
)

media = request.get_media(default_when_empty=self.default_when_empty)
# Support falcon-jsonify.
body = dumps(getattr(request, "json", media))
mimetype = request.options.default_media_type
if request.content_type:
mimetype = request.content_type.partition(";")[0]
@property
def host_url(self):
return self.request.prefix

query = ImmutableMultiDict(list(request.params.items()))
header = Headers(request.headers)
@property
def path(self):
return self.request.path

# Path gets deduced by path finder against spec
parameters = RequestParameters(
query=query,
header=header,
cookie=request.cookies,
)
url_pattern = request.prefix + request.path
return OpenAPIRequest(
full_url_pattern=url_pattern,
method=method,
parameters=parameters,
body=body,
mimetype=mimetype,
@property
def method(self):
return self.request.method.lower()

@property
def body(self):
media = self.request.get_media(
default_when_empty=self.default_when_empty
)
# Support falcon-jsonify.
return dumps(getattr(self.request, "json", media))

@property
def mimetype(self):
if self.request.content_type:
return self.request.content_type.partition(";")[0]
return self.request.options.default_media_type
Loading