diff --git a/openapi_core/contrib/django/handlers.py b/openapi_core/contrib/django/handlers.py index d82e3e31..2209bc8c 100644 --- a/openapi_core/contrib/django/handlers.py +++ b/openapi_core/contrib/django/handlers.py @@ -1,5 +1,6 @@ """OpenAPI core contrib django handlers module""" from typing import Any +from typing import Callable from typing import Dict from typing import Iterable from typing import Optional @@ -14,6 +15,7 @@ from openapi_core.templating.paths.exceptions import PathNotFound from openapi_core.templating.paths.exceptions import ServerNotFound from openapi_core.templating.security.exceptions import SecurityNotFound +from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult class DjangoOpenAPIErrorsHandler: @@ -25,18 +27,15 @@ class DjangoOpenAPIErrorsHandler: MediaTypeNotFound: 415, } - @classmethod - def handle( - cls, + def __call__( + self, errors: Iterable[Exception], - req: HttpRequest, - resp: Optional[HttpResponse] = None, ) -> JsonResponse: - data_errors = [cls.format_openapi_error(err) for err in errors] + data_errors = [self.format_openapi_error(err) for err in errors] data = { "errors": data_errors, } - data_error_max = max(data_errors, key=cls.get_error_status) + data_error_max = max(data_errors, key=self.get_error_status) return JsonResponse(data, status=data_error_max["status"]) @classmethod @@ -52,3 +51,15 @@ def format_openapi_error(cls, error: BaseException) -> Dict[str, Any]: @classmethod def get_error_status(cls, error: Dict[str, Any]) -> str: return str(error["status"]) + + +class DjangoOpenAPIValidRequestHandler: + def __init__(self, req: HttpRequest, view: Callable[[Any], HttpResponse]): + self.req = req + self.view = view + + def __call__( + self, request_unmarshal_result: RequestUnmarshalResult + ) -> HttpResponse: + self.req.openapi = request_unmarshal_result + return self.view(self.req) diff --git a/openapi_core/contrib/django/middlewares.py b/openapi_core/contrib/django/middlewares.py index 6998b9be..db87751f 100644 --- a/openapi_core/contrib/django/middlewares.py +++ b/openapi_core/contrib/django/middlewares.py @@ -3,23 +3,24 @@ from django.conf import settings from django.core.exceptions import ImproperlyConfigured -from django.http import JsonResponse from django.http.request import HttpRequest from django.http.response import HttpResponse from openapi_core.contrib.django.handlers import DjangoOpenAPIErrorsHandler +from openapi_core.contrib.django.handlers import ( + DjangoOpenAPIValidRequestHandler, +) from openapi_core.contrib.django.requests import DjangoOpenAPIRequest from openapi_core.contrib.django.responses import DjangoOpenAPIResponse from openapi_core.unmarshalling.processors import UnmarshallingProcessor -from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult -from openapi_core.unmarshalling.response.datatypes import ( - ResponseUnmarshalResult, -) -class DjangoOpenAPIMiddleware: +class DjangoOpenAPIMiddleware( + UnmarshallingProcessor[HttpRequest, HttpResponse] +): request_cls = DjangoOpenAPIRequest response_cls = DjangoOpenAPIResponse + valid_request_handler_cls = DjangoOpenAPIValidRequestHandler errors_handler = DjangoOpenAPIErrorsHandler() def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]): @@ -31,40 +32,17 @@ def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]): if hasattr(settings, "OPENAPI_RESPONSE_CLS"): self.response_cls = settings.OPENAPI_RESPONSE_CLS - self.processor = UnmarshallingProcessor(settings.OPENAPI_SPEC) + super().__init__(settings.OPENAPI_SPEC) def __call__(self, request: HttpRequest) -> HttpResponse: - openapi_request = self._get_openapi_request(request) - req_result = self.processor.process_request(openapi_request) - if req_result.errors: - response = self._handle_request_errors(req_result, request) - else: - request.openapi = req_result - response = self.get_response(request) - - if self.response_cls is None: - return response - openapi_response = self._get_openapi_response(response) - resp_result = self.processor.process_response( - openapi_request, openapi_response + valid_request_handler = self.valid_request_handler_cls( + request, self.get_response + ) + response = self.handle_request( + request, valid_request_handler, self.errors_handler ) - if resp_result.errors: - return self._handle_response_errors(resp_result, request, response) - - return response - - def _handle_request_errors( - self, request_result: RequestUnmarshalResult, req: HttpRequest - ) -> JsonResponse: - return self.errors_handler.handle(request_result.errors, req, None) - def _handle_response_errors( - self, - response_result: ResponseUnmarshalResult, - req: HttpRequest, - resp: HttpResponse, - ) -> JsonResponse: - return self.errors_handler.handle(response_result.errors, req, resp) + return self.handle_response(request, response, self.errors_handler) def _get_openapi_request( self, request: HttpRequest @@ -76,3 +54,6 @@ def _get_openapi_response( ) -> DjangoOpenAPIResponse: assert self.response_cls is not None return self.response_cls(response) + + def _validate_response(self) -> bool: + return self.response_cls is not None diff --git a/openapi_core/contrib/falcon/handlers.py b/openapi_core/contrib/falcon/handlers.py index 857b6b8b..ccbbe657 100644 --- a/openapi_core/contrib/falcon/handlers.py +++ b/openapi_core/contrib/falcon/handlers.py @@ -15,6 +15,7 @@ from openapi_core.templating.paths.exceptions import PathNotFound from openapi_core.templating.paths.exceptions import ServerNotFound from openapi_core.templating.security.exceptions import SecurityNotFound +from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult class FalconOpenAPIErrorsHandler: @@ -26,24 +27,26 @@ class FalconOpenAPIErrorsHandler: MediaTypeNotFound: 415, } - @classmethod - def handle( - cls, req: Request, resp: Response, errors: Iterable[Exception] - ) -> None: - data_errors = [cls.format_openapi_error(err) for err in errors] + def __init__(self, req: Request, resp: Response): + self.req = req + self.resp = resp + + def __call__(self, errors: Iterable[Exception]) -> Response: + data_errors = [self.format_openapi_error(err) for err in errors] data = { "errors": data_errors, } data_str = dumps(data) - data_error_max = max(data_errors, key=cls.get_error_status) - resp.content_type = MEDIA_JSON - resp.status = getattr( + data_error_max = max(data_errors, key=self.get_error_status) + self.resp.content_type = MEDIA_JSON + self.resp.status = getattr( status_codes, f"HTTP_{data_error_max['status']}", status_codes.HTTP_400, ) - resp.text = data_str - resp.complete = True + self.resp.text = data_str + self.resp.complete = True + return self.resp @classmethod def format_openapi_error(cls, error: BaseException) -> Dict[str, Any]: @@ -58,3 +61,15 @@ def format_openapi_error(cls, error: BaseException) -> Dict[str, Any]: @classmethod def get_error_status(cls, error: Dict[str, Any]) -> int: return int(error["status"]) + + +class FalconOpenAPIValidRequestHandler: + def __init__(self, req: Request, resp: Response): + self.req = req + self.resp = resp + + def __call__( + self, request_unmarshal_result: RequestUnmarshalResult + ) -> Response: + self.req.context.openapi = request_unmarshal_result + return self.resp diff --git a/openapi_core/contrib/falcon/middlewares.py b/openapi_core/contrib/falcon/middlewares.py index f30c7f59..7a7d1533 100644 --- a/openapi_core/contrib/falcon/middlewares.py +++ b/openapi_core/contrib/falcon/middlewares.py @@ -7,22 +7,24 @@ from falcon.response import Response from openapi_core.contrib.falcon.handlers import FalconOpenAPIErrorsHandler +from openapi_core.contrib.falcon.handlers import ( + FalconOpenAPIValidRequestHandler, +) from openapi_core.contrib.falcon.requests import FalconOpenAPIRequest from openapi_core.contrib.falcon.responses import FalconOpenAPIResponse from openapi_core.spec import Spec from openapi_core.unmarshalling.processors import UnmarshallingProcessor -from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult from openapi_core.unmarshalling.request.types import RequestUnmarshallerType -from openapi_core.unmarshalling.response.datatypes import ( - ResponseUnmarshalResult, -) from openapi_core.unmarshalling.response.types import ResponseUnmarshallerType -class FalconOpenAPIMiddleware(UnmarshallingProcessor): +class FalconOpenAPIMiddleware(UnmarshallingProcessor[Request, Response]): request_cls = FalconOpenAPIRequest response_cls = FalconOpenAPIResponse - errors_handler = FalconOpenAPIErrorsHandler() + valid_request_handler_cls = FalconOpenAPIValidRequestHandler + errors_handler_cls: Type[ + FalconOpenAPIErrorsHandler + ] = FalconOpenAPIErrorsHandler def __init__( self, @@ -31,7 +33,9 @@ def __init__( response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None, request_cls: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest, response_cls: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse, - errors_handler: Optional[FalconOpenAPIErrorsHandler] = None, + errors_handler_cls: Type[ + FalconOpenAPIErrorsHandler + ] = FalconOpenAPIErrorsHandler, **unmarshaller_kwargs: Any, ): super().__init__( @@ -42,7 +46,7 @@ def __init__( ) self.request_cls = request_cls or self.request_cls self.response_cls = response_cls or self.response_cls - self.errors_handler = errors_handler or self.errors_handler + self.errors_handler_cls = errors_handler_cls or self.errors_handler_cls @classmethod def from_spec( @@ -52,7 +56,9 @@ def from_spec( response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None, request_cls: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest, response_cls: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse, - errors_handler: Optional[FalconOpenAPIErrorsHandler] = None, + errors_handler_cls: Type[ + FalconOpenAPIErrorsHandler + ] = FalconOpenAPIErrorsHandler, **unmarshaller_kwargs: Any, ) -> "FalconOpenAPIMiddleware": return cls( @@ -61,46 +67,20 @@ def from_spec( response_unmarshaller_cls=response_unmarshaller_cls, request_cls=request_cls, response_cls=response_cls, - errors_handler=errors_handler, + errors_handler_cls=errors_handler_cls, **unmarshaller_kwargs, ) - def process_request(self, req: Request, resp: Response) -> None: # type: ignore - openapi_req = self._get_openapi_request(req) - req.context.openapi = super().process_request(openapi_req) - if req.context.openapi.errors: - return self._handle_request_errors(req, resp, req.context.openapi) + def process_request(self, req: Request, resp: Response) -> None: + valid_handler = self.valid_request_handler_cls(req, resp) + errors_handler = self.errors_handler_cls(req, resp) + self.handle_request(req, valid_handler, errors_handler) - def process_response( # type: ignore + def process_response( self, req: Request, resp: Response, resource: Any, req_succeeded: bool ) -> None: - if self.response_cls is None: - return resp - openapi_req = self._get_openapi_request(req) - openapi_resp = self._get_openapi_response(resp) - resp.context.openapi = super().process_response( - openapi_req, openapi_resp - ) - if resp.context.openapi.errors: - return self._handle_response_errors( - req, resp, resp.context.openapi - ) - - def _handle_request_errors( - self, - req: Request, - resp: Response, - request_result: RequestUnmarshalResult, - ) -> None: - return self.errors_handler.handle(req, resp, request_result.errors) - - def _handle_response_errors( - self, - req: Request, - resp: Response, - response_result: ResponseUnmarshalResult, - ) -> None: - return self.errors_handler.handle(req, resp, response_result.errors) + errors_handler = self.errors_handler_cls(req, resp) + self.handle_response(req, resp, errors_handler) def _get_openapi_request(self, request: Request) -> FalconOpenAPIRequest: return self.request_cls(request) @@ -110,3 +90,6 @@ def _get_openapi_response( ) -> FalconOpenAPIResponse: assert self.response_cls is not None return self.response_cls(response) + + def _validate_response(self) -> bool: + return self.response_cls is not None diff --git a/openapi_core/contrib/flask/decorators.py b/openapi_core/contrib/flask/decorators.py index 7c71ad24..3756f058 100644 --- a/openapi_core/contrib/flask/decorators.py +++ b/openapi_core/contrib/flask/decorators.py @@ -6,25 +6,26 @@ from typing import Type from flask.globals import request -from flask.helpers import make_response from flask.wrappers import Request from flask.wrappers import Response from openapi_core.contrib.flask.handlers import FlaskOpenAPIErrorsHandler +from openapi_core.contrib.flask.handlers import FlaskOpenAPIValidRequestHandler from openapi_core.contrib.flask.providers import FlaskRequestProvider from openapi_core.contrib.flask.requests import FlaskOpenAPIRequest from openapi_core.contrib.flask.responses import FlaskOpenAPIResponse from openapi_core.spec import Spec from openapi_core.unmarshalling.processors import UnmarshallingProcessor -from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult from openapi_core.unmarshalling.request.types import RequestUnmarshallerType -from openapi_core.unmarshalling.response.datatypes import ( - ResponseUnmarshalResult, -) from openapi_core.unmarshalling.response.types import ResponseUnmarshallerType -class FlaskOpenAPIViewDecorator(UnmarshallingProcessor): +class FlaskOpenAPIViewDecorator(UnmarshallingProcessor[Request, Response]): + valid_request_handler_cls = FlaskOpenAPIValidRequestHandler + errors_handler_cls: Type[ + FlaskOpenAPIErrorsHandler + ] = FlaskOpenAPIErrorsHandler + def __init__( self, spec: Spec, @@ -35,7 +36,7 @@ def __init__( Type[FlaskOpenAPIResponse] ] = FlaskOpenAPIResponse, request_provider: Type[FlaskRequestProvider] = FlaskRequestProvider, - openapi_errors_handler: Type[ + errors_handler_cls: Type[ FlaskOpenAPIErrorsHandler ] = FlaskOpenAPIErrorsHandler, **unmarshaller_kwargs: Any, @@ -49,53 +50,23 @@ def __init__( self.request_cls = request_cls self.response_cls = response_cls self.request_provider = request_provider - self.openapi_errors_handler = openapi_errors_handler + self.errors_handler_cls = errors_handler_cls def __call__(self, view: Callable[..., Any]) -> Callable[..., Any]: @wraps(view) def decorated(*args: Any, **kwargs: Any) -> Response: request = self._get_request() - openapi_request = self._get_openapi_request(request) - request_result = self.process_request(openapi_request) - if request_result.errors: - return self._handle_request_errors(request_result) - response = self._handle_request_view( - request_result, view, *args, **kwargs + valid_request_handler = self.valid_request_handler_cls( + request, view, *args, **kwargs ) - if self.response_cls is None: - return response - openapi_response = self._get_openapi_response(response) - response_result = self.process_response( - openapi_request, openapi_response + errors_handler = self.errors_handler_cls() + response = self.handle_request( + request, valid_request_handler, errors_handler ) - if response_result.errors: - return self._handle_response_errors(response_result) - return response + return self.handle_response(request, response, errors_handler) return decorated - def _handle_request_view( - self, - request_result: RequestUnmarshalResult, - view: Callable[[Any], Response], - *args: Any, - **kwargs: Any, - ) -> Response: - request = self._get_request() - request.openapi = request_result # type: ignore - rv = view(*args, **kwargs) - return make_response(rv) - - def _handle_request_errors( - self, request_result: RequestUnmarshalResult - ) -> Response: - return self.openapi_errors_handler.handle(request_result.errors) - - def _handle_response_errors( - self, response_result: ResponseUnmarshalResult - ) -> Response: - return self.openapi_errors_handler.handle(response_result.errors) - def _get_request(self) -> Request: return request @@ -108,6 +79,9 @@ def _get_openapi_response( assert self.response_cls is not None return self.response_cls(response) + def _validate_response(self) -> bool: + return self.response_cls is not None + @classmethod def from_spec( cls, @@ -117,7 +91,7 @@ def from_spec( request_cls: Type[FlaskOpenAPIRequest] = FlaskOpenAPIRequest, response_cls: Type[FlaskOpenAPIResponse] = FlaskOpenAPIResponse, request_provider: Type[FlaskRequestProvider] = FlaskRequestProvider, - openapi_errors_handler: Type[ + errors_handler_cls: Type[ FlaskOpenAPIErrorsHandler ] = FlaskOpenAPIErrorsHandler, **unmarshaller_kwargs: Any, @@ -129,6 +103,6 @@ def from_spec( request_cls=request_cls, response_cls=response_cls, request_provider=request_provider, - openapi_errors_handler=openapi_errors_handler, + errors_handler_cls=errors_handler_cls, **unmarshaller_kwargs, ) diff --git a/openapi_core/contrib/flask/handlers.py b/openapi_core/contrib/flask/handlers.py index 3e50ad76..e1a20fc4 100644 --- a/openapi_core/contrib/flask/handlers.py +++ b/openapi_core/contrib/flask/handlers.py @@ -1,11 +1,14 @@ """OpenAPI core contrib flask handlers module""" from typing import Any +from typing import Callable from typing import Dict from typing import Iterable from typing import Type from flask.globals import current_app +from flask.helpers import make_response from flask.json import dumps +from flask.wrappers import Request from flask.wrappers import Response from openapi_core.templating.media_types.exceptions import MediaTypeNotFound @@ -13,6 +16,7 @@ from openapi_core.templating.paths.exceptions import PathNotFound from openapi_core.templating.paths.exceptions import ServerNotFound from openapi_core.templating.security.exceptions import SecurityNotFound +from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult class FlaskOpenAPIErrorsHandler: @@ -24,13 +28,12 @@ class FlaskOpenAPIErrorsHandler: MediaTypeNotFound: 415, } - @classmethod - def handle(cls, errors: Iterable[BaseException]) -> Response: - data_errors = [cls.format_openapi_error(err) for err in errors] + def __call__(self, errors: Iterable[Exception]) -> Response: + data_errors = [self.format_openapi_error(err) for err in errors] data = { "errors": data_errors, } - data_error_max = max(data_errors, key=cls.get_error_status) + data_error_max = max(data_errors, key=self.get_error_status) status = data_error_max["status"] return current_app.response_class( dumps(data), status=status, mimetype="application/json" @@ -49,3 +52,24 @@ def format_openapi_error(cls, error: BaseException) -> Dict[str, Any]: @classmethod def get_error_status(cls, error: Dict[str, Any]) -> int: return int(error["status"]) + + +class FlaskOpenAPIValidRequestHandler: + def __init__( + self, + req: Request, + view: Callable[[Any], Response], + *view_args: Any, + **view_kwargs: Any, + ): + self.req = req + self.view = view + self.view_args = view_args + self.view_kwargs = view_kwargs + + def __call__( + self, request_unmarshal_result: RequestUnmarshalResult + ) -> Response: + self.req.openapi = request_unmarshal_result # type: ignore + rv = self.view(*self.view_args, **self.view_kwargs) + return make_response(rv) diff --git a/openapi_core/contrib/flask/views.py b/openapi_core/contrib/flask/views.py index 71e1afe7..39bef43c 100644 --- a/openapi_core/contrib/flask/views.py +++ b/openapi_core/contrib/flask/views.py @@ -15,13 +15,14 @@ class FlaskOpenAPIView(MethodView): def __init__(self, spec: Spec, **unmarshaller_kwargs: Any): super().__init__() - self.spec = spec self.decorator = FlaskOpenAPIViewDecorator( - self.spec, - openapi_errors_handler=self.openapi_errors_handler, + spec, + errors_handler_cls=self.openapi_errors_handler, **unmarshaller_kwargs, ) def dispatch_request(self, *args: Any, **kwargs: Any) -> Any: - return self.decorator(super().dispatch_request)(*args, **kwargs) + response = self.decorator(super().dispatch_request)(*args, **kwargs) + + return response diff --git a/openapi_core/typing.py b/openapi_core/typing.py new file mode 100644 index 00000000..78b66b24 --- /dev/null +++ b/openapi_core/typing.py @@ -0,0 +1,13 @@ +from typing import Callable +from typing import Iterable +from typing import TypeVar + +from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult + +#: The type of request within an integration. +RequestType = TypeVar("RequestType") +#: The type of response within an integration. +ResponseType = TypeVar("ResponseType") + +ErrorsHandlerCallable = Callable[[Iterable[Exception]], ResponseType] +ValidRequestHandlerCallable = Callable[[RequestUnmarshalResult], ResponseType] diff --git a/openapi_core/unmarshalling/processors.py b/openapi_core/unmarshalling/processors.py index 5a1458c1..fcec7c26 100644 --- a/openapi_core/unmarshalling/processors.py +++ b/openapi_core/unmarshalling/processors.py @@ -1,21 +1,27 @@ """OpenAPI core unmarshalling processors module""" from typing import Any +from typing import Generic from typing import Optional -from typing import Type from openapi_core.protocols import Request from openapi_core.protocols import Response from openapi_core.shortcuts import get_classes from openapi_core.spec import Spec -from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult +from openapi_core.typing import ErrorsHandlerCallable +from openapi_core.typing import RequestType +from openapi_core.typing import ResponseType +from openapi_core.typing import ValidRequestHandlerCallable +from openapi_core.unmarshalling.request.processors import ( + RequestUnmarshallingProcessor, +) from openapi_core.unmarshalling.request.types import RequestUnmarshallerType -from openapi_core.unmarshalling.response.datatypes import ( - ResponseUnmarshalResult, +from openapi_core.unmarshalling.response.processors import ( + ResponseUnmarshallingProcessor, ) from openapi_core.unmarshalling.response.types import ResponseUnmarshallerType -class UnmarshallingProcessor: +class UnmarshallingProcessor(Generic[RequestType, ResponseType]): def __init__( self, spec: Spec, @@ -23,27 +29,63 @@ def __init__( response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None, **unmarshaller_kwargs: Any, ): - self.spec = spec if ( request_unmarshaller_cls is None or response_unmarshaller_cls is None ): - classes = get_classes(self.spec) + classes = get_classes(spec) if request_unmarshaller_cls is None: request_unmarshaller_cls = classes.request_unmarshaller_cls if response_unmarshaller_cls is None: response_unmarshaller_cls = classes.response_unmarshaller_cls - self.request_unmarshaller = request_unmarshaller_cls( - self.spec, **unmarshaller_kwargs + + self.request_processor = RequestUnmarshallingProcessor( + spec, + request_unmarshaller_cls, + **unmarshaller_kwargs, ) - self.response_unmarshaller = response_unmarshaller_cls( - self.spec, **unmarshaller_kwargs + self.response_processor = ResponseUnmarshallingProcessor( + spec, + response_unmarshaller_cls, + **unmarshaller_kwargs, ) - def process_request(self, request: Request) -> RequestUnmarshalResult: - return self.request_unmarshaller.unmarshal(request) + def _get_openapi_request(self, request: RequestType) -> Request: + raise NotImplementedError + + def _get_openapi_response(self, response: ResponseType) -> Response: + raise NotImplementedError - def process_response( - self, request: Request, response: Response - ) -> ResponseUnmarshalResult: - return self.response_unmarshaller.unmarshal(request, response) + def _validate_response(self) -> bool: + raise NotImplementedError + + def handle_request( + self, + request: RequestType, + valid_handler: ValidRequestHandlerCallable[ResponseType], + errors_handler: ErrorsHandlerCallable[ResponseType], + ) -> ResponseType: + openapi_request = self._get_openapi_request(request) + request_unmarshal_result = self.request_processor.process( + openapi_request + ) + if request_unmarshal_result.errors: + return errors_handler(request_unmarshal_result.errors) + return valid_handler(request_unmarshal_result) + + def handle_response( + self, + request: RequestType, + response: ResponseType, + errors_handler: ErrorsHandlerCallable[ResponseType], + ) -> ResponseType: + if not self._validate_response(): + return response + openapi_request = self._get_openapi_request(request) + openapi_response = self._get_openapi_response(response) + response_unmarshal_result = self.response_processor.process( + openapi_request, openapi_response + ) + if response_unmarshal_result.errors: + return errors_handler(response_unmarshal_result.errors) + return response diff --git a/openapi_core/unmarshalling/request/processors.py b/openapi_core/unmarshalling/request/processors.py new file mode 100644 index 00000000..1719605e --- /dev/null +++ b/openapi_core/unmarshalling/request/processors.py @@ -0,0 +1,33 @@ +from typing import Any +from typing import Optional + +from openapi_core.protocols import Request +from openapi_core.spec import Spec +from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult +from openapi_core.unmarshalling.request.protocols import RequestUnmarshaller +from openapi_core.unmarshalling.request.types import RequestUnmarshallerType + + +class RequestUnmarshallingProcessor: + def __init__( + self, + spec: Spec, + request_unmarshaller_cls: RequestUnmarshallerType, + **unmarshaller_kwargs: Any + ) -> None: + self.spec = spec + self.request_unmarshaller_cls = request_unmarshaller_cls + self.unmarshaller_kwargs = unmarshaller_kwargs + + self._request_unmarshaller_cached: Optional[RequestUnmarshaller] = None + + @property + def request_unmarshaller(self) -> RequestUnmarshaller: + if self._request_unmarshaller_cached is None: + self._request_unmarshaller_cached = self.request_unmarshaller_cls( + self.spec, **self.unmarshaller_kwargs + ) + return self._request_unmarshaller_cached + + def process(self, request: Request) -> RequestUnmarshalResult: + return self.request_unmarshaller.unmarshal(request) diff --git a/openapi_core/unmarshalling/response/processors.py b/openapi_core/unmarshalling/response/processors.py new file mode 100644 index 00000000..517af232 --- /dev/null +++ b/openapi_core/unmarshalling/response/processors.py @@ -0,0 +1,42 @@ +from typing import Any +from typing import Optional + +from openapi_core.protocols import Request +from openapi_core.protocols import Response +from openapi_core.spec import Spec +from openapi_core.unmarshalling.response.datatypes import ( + ResponseUnmarshalResult, +) +from openapi_core.unmarshalling.response.protocols import ResponseUnmarshaller +from openapi_core.unmarshalling.response.types import ResponseUnmarshallerType + + +class ResponseUnmarshallingProcessor: + def __init__( + self, + spec: Spec, + response_unmarshaller_cls: ResponseUnmarshallerType, + **unmarshaller_kwargs: Any + ) -> None: + self.spec = spec + self.response_unmarshaller_cls = response_unmarshaller_cls + self.unmarshaller_kwargs = unmarshaller_kwargs + + self._response_unmarshaller_cached: Optional[ + ResponseUnmarshaller + ] = None + + @property + def response_unmarshaller(self) -> ResponseUnmarshaller: + if self._response_unmarshaller_cached is None: + self._response_unmarshaller_cached = ( + self.response_unmarshaller_cls( + self.spec, **self.unmarshaller_kwargs + ) + ) + return self._response_unmarshaller_cached + + def process( + self, request: Request, response: Response + ) -> ResponseUnmarshalResult: + return self.response_unmarshaller.unmarshal(request, response)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: