Skip to content

Commit 22ace6d

Browse files
committed
Unmarshalling processor enhancement
1 parent d7d1fac commit 22ace6d

File tree

11 files changed

+286
-167
lines changed

11 files changed

+286
-167
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: 17 additions & 36 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_cls = DjangoOpenAPIRequest
2222
response_cls = DjangoOpenAPIResponse
23+
valid_request_handler_cls = DjangoOpenAPIValidRequestHandler
2324
errors_handler = DjangoOpenAPIErrorsHandler()
2425

2526
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
@@ -31,40 +32,17 @@ def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
3132
if hasattr(settings, "OPENAPI_RESPONSE_CLS"):
3233
self.response_cls = settings.OPENAPI_RESPONSE_CLS
3334

34-
self.processor = UnmarshallingProcessor(settings.OPENAPI_SPEC)
35+
super().__init__(settings.OPENAPI_SPEC)
3536

3637
def __call__(self, request: HttpRequest) -> HttpResponse:
37-
openapi_request = self._get_openapi_request(request)
38-
req_result = self.processor.process_request(openapi_request)
39-
if req_result.errors:
40-
response = self._handle_request_errors(req_result, request)
41-
else:
42-
request.openapi = req_result
43-
response = self.get_response(request)
44-
45-
if self.response_cls is None:
46-
return response
47-
openapi_response = self._get_openapi_response(response)
48-
resp_result = self.processor.process_response(
49-
openapi_request, openapi_response
38+
valid_request_handler = self.valid_request_handler_cls(
39+
request, self.get_response
40+
)
41+
response = self.handle_request(
42+
request, valid_request_handler, self.errors_handler
5043
)
51-
if resp_result.errors:
52-
return self._handle_response_errors(resp_result, request, response)
53-
54-
return response
55-
56-
def _handle_request_errors(
57-
self, request_result: RequestUnmarshalResult, req: HttpRequest
58-
) -> JsonResponse:
59-
return self.errors_handler.handle(request_result.errors, req, None)
6044

61-
def _handle_response_errors(
62-
self,
63-
response_result: ResponseUnmarshalResult,
64-
req: HttpRequest,
65-
resp: HttpResponse,
66-
) -> JsonResponse:
67-
return self.errors_handler.handle(response_result.errors, req, resp)
45+
return self.handle_response(request, response, self.errors_handler)
6846

6947
def _get_openapi_request(
7048
self, request: HttpRequest
@@ -76,3 +54,6 @@ def _get_openapi_response(
7654
) -> DjangoOpenAPIResponse:
7755
assert self.response_cls is not None
7856
return self.response_cls(response)
57+
58+
def _validate_response(self) -> bool:
59+
return self.response_cls is not None

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: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,24 @@
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):
21+
class FalconOpenAPIMiddleware(UnmarshallingProcessor[Request, Response]):
2322
request_cls = FalconOpenAPIRequest
2423
response_cls = FalconOpenAPIResponse
25-
errors_handler = FalconOpenAPIErrorsHandler()
24+
valid_request_handler_cls = FalconOpenAPIValidRequestHandler
25+
errors_handler_cls: Type[
26+
FalconOpenAPIErrorsHandler
27+
] = FalconOpenAPIErrorsHandler
2628

2729
def __init__(
2830
self,
@@ -31,7 +33,9 @@ def __init__(
3133
response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None,
3234
request_cls: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
3335
response_cls: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse,
34-
errors_handler: Optional[FalconOpenAPIErrorsHandler] = None,
36+
errors_handler_cls: Type[
37+
FalconOpenAPIErrorsHandler
38+
] = FalconOpenAPIErrorsHandler,
3539
**unmarshaller_kwargs: Any,
3640
):
3741
super().__init__(
@@ -42,7 +46,7 @@ def __init__(
4246
)
4347
self.request_cls = request_cls or self.request_cls
4448
self.response_cls = response_cls or self.response_cls
45-
self.errors_handler = errors_handler or self.errors_handler
49+
self.errors_handler_cls = errors_handler_cls or self.errors_handler_cls
4650

4751
@classmethod
4852
def from_spec(
@@ -52,7 +56,9 @@ def from_spec(
5256
response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None,
5357
request_cls: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
5458
response_cls: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse,
55-
errors_handler: Optional[FalconOpenAPIErrorsHandler] = None,
59+
errors_handler_cls: Type[
60+
FalconOpenAPIErrorsHandler
61+
] = FalconOpenAPIErrorsHandler,
5662
**unmarshaller_kwargs: Any,
5763
) -> "FalconOpenAPIMiddleware":
5864
return cls(
@@ -61,46 +67,20 @@ def from_spec(
6167
response_unmarshaller_cls=response_unmarshaller_cls,
6268
request_cls=request_cls,
6369
response_cls=response_cls,
64-
errors_handler=errors_handler,
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-
if self.response_cls is None:
78-
return resp
79-
openapi_req = self._get_openapi_request(req)
80-
openapi_resp = self._get_openapi_response(resp)
81-
resp.context.openapi = super().process_response(
82-
openapi_req, openapi_resp
83-
)
84-
if resp.context.openapi.errors:
85-
return self._handle_response_errors(
86-
req, resp, resp.context.openapi
87-
)
88-
89-
def _handle_request_errors(
90-
self,
91-
req: Request,
92-
resp: Response,
93-
request_result: RequestUnmarshalResult,
94-
) -> None:
95-
return self.errors_handler.handle(req, resp, request_result.errors)
96-
97-
def _handle_response_errors(
98-
self,
99-
req: Request,
100-
resp: Response,
101-
response_result: ResponseUnmarshalResult,
102-
) -> None:
103-
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)
10484

10585
def _get_openapi_request(self, request: Request) -> FalconOpenAPIRequest:
10686
return self.request_cls(request)
@@ -110,3 +90,6 @@ def _get_openapi_response(
11090
) -> FalconOpenAPIResponse:
11191
assert self.response_cls is not None
11292
return self.response_cls(response)
93+
94+
def _validate_response(self) -> bool:
95+
return self.response_cls is not None

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