Skip to content

Commit 0f85311

Browse files
committed
Unmarshalling processor enhancement
1 parent d60be8c commit 0f85311

File tree

11 files changed

+284
-173
lines changed

11 files changed

+284
-173
lines changed

openapi_core/contrib/django/handlers.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""OpenAPI core contrib django handlers module"""
22
from typing import Any
3+
from typing import Callable
34
from typing import Dict
45
from typing import Iterable
56
from typing import Optional
@@ -14,6 +15,7 @@
1415
from openapi_core.templating.paths.exceptions import PathNotFound
1516
from openapi_core.templating.paths.exceptions import ServerNotFound
1617
from openapi_core.templating.security.exceptions import SecurityNotFound
18+
from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult
1719

1820

1921
class DjangoOpenAPIErrorsHandler:
@@ -25,18 +27,15 @@ class DjangoOpenAPIErrorsHandler:
2527
MediaTypeNotFound: 415,
2628
}
2729

28-
@classmethod
29-
def handle(
30-
cls,
30+
def __call__(
31+
self,
3132
errors: Iterable[Exception],
32-
req: HttpRequest,
33-
resp: Optional[HttpResponse] = None,
3433
) -> JsonResponse:
35-
data_errors = [cls.format_openapi_error(err) for err in errors]
34+
data_errors = [self.format_openapi_error(err) for err in errors]
3635
data = {
3736
"errors": data_errors,
3837
}
39-
data_error_max = max(data_errors, key=cls.get_error_status)
38+
data_error_max = max(data_errors, key=self.get_error_status)
4039
return JsonResponse(data, status=data_error_max["status"])
4140

4241
@classmethod
@@ -52,3 +51,15 @@ def format_openapi_error(cls, error: BaseException) -> Dict[str, Any]:
5251
@classmethod
5352
def get_error_status(cls, error: Dict[str, Any]) -> str:
5453
return str(error["status"])
54+
55+
56+
class DjangoOpenAPIValidRequestHandler:
57+
def __init__(self, req: HttpRequest, view: Callable[[Any], HttpResponse]):
58+
self.req = req
59+
self.view = view
60+
61+
def __call__(
62+
self, request_unmarshal_result: RequestUnmarshalResult
63+
) -> HttpResponse:
64+
self.req.openapi = request_unmarshal_result
65+
return self.view(self.req)

openapi_core/contrib/django/middlewares.py

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,24 @@
33

44
from django.conf import settings
55
from django.core.exceptions import ImproperlyConfigured
6-
from django.http import JsonResponse
76
from django.http.request import HttpRequest
87
from django.http.response import HttpResponse
98

109
from openapi_core.contrib.django.handlers import DjangoOpenAPIErrorsHandler
10+
from openapi_core.contrib.django.handlers import (
11+
DjangoOpenAPIValidRequestHandler,
12+
)
1113
from openapi_core.contrib.django.requests import DjangoOpenAPIRequest
1214
from openapi_core.contrib.django.responses import DjangoOpenAPIResponse
1315
from openapi_core.unmarshalling.processors import UnmarshallingProcessor
14-
from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult
15-
from openapi_core.unmarshalling.response.datatypes import (
16-
ResponseUnmarshalResult,
17-
)
1816

1917

20-
class DjangoOpenAPIMiddleware:
18+
class DjangoOpenAPIMiddleware(
19+
UnmarshallingProcessor[HttpRequest, HttpResponse]
20+
):
2121
request_class = DjangoOpenAPIRequest
2222
response_class = DjangoOpenAPIResponse
23+
valid_request_handler_cls = DjangoOpenAPIValidRequestHandler
2324
errors_handler = DjangoOpenAPIErrorsHandler()
2425

2526
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
@@ -28,38 +29,17 @@ def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
2829
if not hasattr(settings, "OPENAPI_SPEC"):
2930
raise ImproperlyConfigured("OPENAPI_SPEC not defined in settings")
3031

31-
self.processor = UnmarshallingProcessor(settings.OPENAPI_SPEC)
32+
super().__init__(settings.OPENAPI_SPEC)
3233

3334
def __call__(self, request: HttpRequest) -> HttpResponse:
34-
openapi_request = self._get_openapi_request(request)
35-
req_result = self.processor.process_request(openapi_request)
36-
if req_result.errors:
37-
response = self._handle_request_errors(req_result, request)
38-
else:
39-
request.openapi = req_result
40-
response = self.get_response(request)
41-
42-
openapi_response = self._get_openapi_response(response)
43-
resp_result = self.processor.process_response(
44-
openapi_request, openapi_response
35+
valid_request_handler = self.valid_request_handler_cls(
36+
request, self.get_response
37+
)
38+
response = self.handle_request(
39+
request, valid_request_handler, self.errors_handler
4540
)
46-
if resp_result.errors:
47-
return self._handle_response_errors(resp_result, request, response)
48-
49-
return response
50-
51-
def _handle_request_errors(
52-
self, request_result: RequestUnmarshalResult, req: HttpRequest
53-
) -> JsonResponse:
54-
return self.errors_handler.handle(request_result.errors, req, None)
5541

56-
def _handle_response_errors(
57-
self,
58-
response_result: ResponseUnmarshalResult,
59-
req: HttpRequest,
60-
resp: HttpResponse,
61-
) -> JsonResponse:
62-
return self.errors_handler.handle(response_result.errors, req, resp)
42+
return self.handle_response(request, response, self.errors_handler)
6343

6444
def _get_openapi_request(
6545
self, request: HttpRequest

openapi_core/contrib/falcon/handlers.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from openapi_core.templating.paths.exceptions import PathNotFound
1616
from openapi_core.templating.paths.exceptions import ServerNotFound
1717
from openapi_core.templating.security.exceptions import SecurityNotFound
18+
from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult
1819

1920

2021
class FalconOpenAPIErrorsHandler:
@@ -26,24 +27,26 @@ class FalconOpenAPIErrorsHandler:
2627
MediaTypeNotFound: 415,
2728
}
2829

29-
@classmethod
30-
def handle(
31-
cls, req: Request, resp: Response, errors: Iterable[Exception]
32-
) -> None:
33-
data_errors = [cls.format_openapi_error(err) for err in errors]
30+
def __init__(self, req: Request, resp: Response):
31+
self.req = req
32+
self.resp = resp
33+
34+
def __call__(self, errors: Iterable[Exception]) -> Response:
35+
data_errors = [self.format_openapi_error(err) for err in errors]
3436
data = {
3537
"errors": data_errors,
3638
}
3739
data_str = dumps(data)
38-
data_error_max = max(data_errors, key=cls.get_error_status)
39-
resp.content_type = MEDIA_JSON
40-
resp.status = getattr(
40+
data_error_max = max(data_errors, key=self.get_error_status)
41+
self.resp.content_type = MEDIA_JSON
42+
self.resp.status = getattr(
4143
status_codes,
4244
f"HTTP_{data_error_max['status']}",
4345
status_codes.HTTP_400,
4446
)
45-
resp.text = data_str
46-
resp.complete = True
47+
self.resp.text = data_str
48+
self.resp.complete = True
49+
return self.resp
4750

4851
@classmethod
4952
def format_openapi_error(cls, error: BaseException) -> Dict[str, Any]:
@@ -58,3 +61,15 @@ def format_openapi_error(cls, error: BaseException) -> Dict[str, Any]:
5861
@classmethod
5962
def get_error_status(cls, error: Dict[str, Any]) -> int:
6063
return int(error["status"])
64+
65+
66+
class FalconOpenAPIValidRequestHandler:
67+
def __init__(self, req: Request, resp: Response):
68+
self.req = req
69+
self.resp = resp
70+
71+
def __call__(
72+
self, request_unmarshal_result: RequestUnmarshalResult
73+
) -> Response:
74+
self.req.context.openapi = request_unmarshal_result
75+
return self.resp

openapi_core/contrib/falcon/middlewares.py

Lines changed: 35 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,35 @@
77
from falcon.response import Response
88

99
from openapi_core.contrib.falcon.handlers import FalconOpenAPIErrorsHandler
10+
from openapi_core.contrib.falcon.handlers import (
11+
FalconOpenAPIValidRequestHandler,
12+
)
1013
from openapi_core.contrib.falcon.requests import FalconOpenAPIRequest
1114
from openapi_core.contrib.falcon.responses import FalconOpenAPIResponse
1215
from openapi_core.spec import Spec
1316
from openapi_core.unmarshalling.processors import UnmarshallingProcessor
14-
from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult
1517
from openapi_core.unmarshalling.request.types import RequestUnmarshallerType
16-
from openapi_core.unmarshalling.response.datatypes import (
17-
ResponseUnmarshalResult,
18-
)
1918
from openapi_core.unmarshalling.response.types import ResponseUnmarshallerType
2019

2120

22-
class FalconOpenAPIMiddleware(UnmarshallingProcessor):
23-
request_class = FalconOpenAPIRequest
24-
response_class = FalconOpenAPIResponse
25-
errors_handler = FalconOpenAPIErrorsHandler()
21+
class FalconOpenAPIMiddleware(UnmarshallingProcessor[Request, Response]):
22+
request_cls = FalconOpenAPIRequest
23+
response_cls = FalconOpenAPIResponse
24+
valid_request_handler_cls = FalconOpenAPIValidRequestHandler
25+
errors_handler_cls: Type[
26+
FalconOpenAPIErrorsHandler
27+
] = FalconOpenAPIErrorsHandler
2628

2729
def __init__(
2830
self,
2931
spec: Spec,
3032
request_unmarshaller_cls: Optional[RequestUnmarshallerType] = None,
3133
response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None,
32-
request_class: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
33-
response_class: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse,
34-
errors_handler: Optional[FalconOpenAPIErrorsHandler] = None,
34+
request_cls: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
35+
response_cls: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse,
36+
errors_handler_cls: Type[
37+
FalconOpenAPIErrorsHandler
38+
] = FalconOpenAPIErrorsHandler,
3539
**unmarshaller_kwargs: Any,
3640
):
3741
super().__init__(
@@ -40,70 +44,48 @@ def __init__(
4044
response_unmarshaller_cls=response_unmarshaller_cls,
4145
**unmarshaller_kwargs,
4246
)
43-
self.request_class = request_class or self.request_class
44-
self.response_class = response_class or self.response_class
45-
self.errors_handler = errors_handler or self.errors_handler
47+
self.request_cls = request_cls or self.request_cls
48+
self.response_cls = response_cls or self.response_cls
49+
self.errors_handler_cls = errors_handler_cls or self.errors_handler_cls
4650

4751
@classmethod
4852
def from_spec(
4953
cls,
5054
spec: Spec,
5155
request_unmarshaller_cls: Optional[RequestUnmarshallerType] = None,
5256
response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None,
53-
request_class: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
54-
response_class: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse,
55-
errors_handler: Optional[FalconOpenAPIErrorsHandler] = None,
57+
request_cls: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
58+
response_cls: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse,
59+
errors_handler_cls: Type[
60+
FalconOpenAPIErrorsHandler
61+
] = FalconOpenAPIErrorsHandler,
5662
**unmarshaller_kwargs: Any,
5763
) -> "FalconOpenAPIMiddleware":
5864
return cls(
5965
spec,
6066
request_unmarshaller_cls=request_unmarshaller_cls,
6167
response_unmarshaller_cls=response_unmarshaller_cls,
62-
request_class=request_class,
63-
response_class=response_class,
64-
errors_handler=errors_handler,
68+
request_cls=request_cls,
69+
response_cls=response_cls,
70+
errors_handler_cls=errors_handler_cls,
6571
**unmarshaller_kwargs,
6672
)
6773

68-
def process_request(self, req: Request, resp: Response) -> None: # type: ignore
69-
openapi_req = self._get_openapi_request(req)
70-
req.context.openapi = super().process_request(openapi_req)
71-
if req.context.openapi.errors:
72-
return self._handle_request_errors(req, resp, req.context.openapi)
74+
def process_request(self, req: Request, resp: Response) -> None:
75+
valid_handler = self.valid_request_handler_cls(req, resp)
76+
errors_handler = self.errors_handler_cls(req, resp)
77+
self.handle_request(req, valid_handler, errors_handler)
7378

74-
def process_response( # type: ignore
79+
def process_response(
7580
self, req: Request, resp: Response, resource: Any, req_succeeded: bool
7681
) -> None:
77-
openapi_req = self._get_openapi_request(req)
78-
openapi_resp = self._get_openapi_response(resp)
79-
resp.context.openapi = super().process_response(
80-
openapi_req, openapi_resp
81-
)
82-
if resp.context.openapi.errors:
83-
return self._handle_response_errors(
84-
req, resp, resp.context.openapi
85-
)
86-
87-
def _handle_request_errors(
88-
self,
89-
req: Request,
90-
resp: Response,
91-
request_result: RequestUnmarshalResult,
92-
) -> None:
93-
return self.errors_handler.handle(req, resp, request_result.errors)
94-
95-
def _handle_response_errors(
96-
self,
97-
req: Request,
98-
resp: Response,
99-
response_result: ResponseUnmarshalResult,
100-
) -> None:
101-
return self.errors_handler.handle(req, resp, response_result.errors)
82+
errors_handler = self.errors_handler_cls(req, resp)
83+
self.handle_response(req, resp, errors_handler)
10284

10385
def _get_openapi_request(self, request: Request) -> FalconOpenAPIRequest:
104-
return self.request_class(request)
86+
return self.request_cls(request)
10587

10688
def _get_openapi_response(
10789
self, response: Response
10890
) -> FalconOpenAPIResponse:
109-
return self.response_class(response)
91+
return self.response_cls(response)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy