Skip to content

Commit 2a330f3

Browse files
committedJan 20, 2023
Webhooks support
1 parent e576212 commit 2a330f3

27 files changed

+1101
-345
lines changed
 

‎README.rst

+22-6
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ Use ``validate_request`` function to validate request against a given spec.
8080
# raise error if request is invalid
8181
result = validate_request(request, spec=spec)
8282
83+
Request object should implement OpenAPI Request protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).
84+
85+
Use the same function to validate webhook request against a given spec.
86+
87+
.. code-block:: python
88+
89+
# raise error if request is invalid
90+
result = validate_request(webhook_request, spec=spec)
91+
92+
Webhook request object should implement OpenAPI WebhookRequest protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).
93+
8394
Retrieve request data from validation result
8495

8596
.. code-block:: python
@@ -95,8 +106,6 @@ Retrieve request data from validation result
95106
# get security data
96107
validated_security = result.security
97108
98-
Request object should implement OpenAPI Request protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).
99-
100109
Response
101110
********
102111

@@ -109,7 +118,16 @@ Use ``validate_response`` function to validate response against a given spec.
109118
# raise error if response is invalid
110119
result = validate_response(request, response, spec=spec)
111120
112-
and unmarshal response data from validation result
121+
Response object should implement OpenAPI Response protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).
122+
123+
Use the same function to validate response from webhook request against a given spec.
124+
125+
.. code-block:: python
126+
127+
# raise error if request is invalid
128+
result = validate_response(webhook_request, response, spec=spec)
129+
130+
Retrieve response data from validation result
113131

114132
.. code-block:: python
115133
@@ -119,12 +137,10 @@ and unmarshal response data from validation result
119137
# get data
120138
validated_data = result.data
121139
122-
Response object should implement OpenAPI Response protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).
123-
124140
In order to explicitly validate a:
125141

126142
* OpenAPI 3.0 spec, import ``V30RequestValidator`` or ``V30ResponseValidator``
127-
* OpenAPI 3.1 spec, import ``V31RequestValidator`` or ``V31ResponseValidator``
143+
* OpenAPI 3.1 spec, import ``V31RequestValidator`` or ``V31ResponseValidator`` or ``V31WebhookRequestValidator`` or ``V31WebhookResponseValidator``
128144

129145
.. code:: python
130146

‎docs/integrations.rst

+11
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,17 @@ You can use ``RequestsOpenAPIResponse`` as a Requests response factory:
240240
result = validate_response(openapi_request, openapi_response, spec=spec)
241241
242242
243+
You can use ``RequestsOpenAPIWebhookRequest`` as a Requests webhook request factory:
244+
245+
.. code-block:: python
246+
247+
from openapi_core import validate_request
248+
from openapi_core.contrib.requests import RequestsOpenAPIWebhookRequest
249+
250+
openapi_webhook_request = RequestsOpenAPIWebhookRequest(requests_request, "my_webhook")
251+
result = validate_request(openapi_webhook_request, spec=spec)
252+
253+
243254
Starlette
244255
---------
245256

‎docs/usage.rst

+20-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ Use ``validate_request`` function to validate request against a given spec. By d
2323
# raise error if request is invalid
2424
result = validate_request(request, spec=spec)
2525
26+
Request object should implement OpenAPI Request protocol (See :doc:`integrations`).
27+
28+
Use the same function to validate webhook request against a given spec.
29+
30+
.. code-block:: python
31+
32+
# raise error if request is invalid
33+
result = validate_request(webhook_request, spec=spec)
34+
35+
Webhook request object should implement OpenAPI WebhookRequest protocol (See :doc:`integrations`).
36+
2637
Retrieve validated and unmarshalled request data from validation result
2738

2839
.. code-block:: python
@@ -38,8 +49,6 @@ Retrieve validated and unmarshalled request data from validation result
3849
# get security data
3950
validated_security = result.security
4051
41-
Request object should implement OpenAPI Request protocol (See :doc:`integrations`).
42-
4352
Response
4453
--------
4554

@@ -52,6 +61,15 @@ Use ``validate_response`` function to validate response against a given spec. By
5261
# raise error if response is invalid
5362
result = validate_response(request, response, spec=spec)
5463
64+
Response object should implement OpenAPI Response protocol (See :doc:`integrations`).
65+
66+
Use the same function to validate response from webhook request against a given spec.
67+
68+
.. code-block:: python
69+
70+
# raise error if request is invalid
71+
result = validate_response(webhook_request, response, spec=spec)
72+
5573
Retrieve validated and unmarshalled response data from validation result
5674

5775
.. code-block:: python
@@ -62,8 +80,6 @@ Retrieve validated and unmarshalled response data from validation result
6280
# get data
6381
validated_data = result.data
6482
65-
Response object should implement OpenAPI Response protocol (See :doc:`integrations`).
66-
6783
Security
6884
--------
6985

‎openapi_core/__init__.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""OpenAPI core module"""
22
from openapi_core.spec import Spec
33
from openapi_core.validation.request import V3RequestValidator
4+
from openapi_core.validation.request import V3WebhookRequestValidator
45
from openapi_core.validation.request import V30RequestValidator
56
from openapi_core.validation.request import V31RequestValidator
7+
from openapi_core.validation.request import V31WebhookRequestValidator
68
from openapi_core.validation.request import openapi_request_body_validator
79
from openapi_core.validation.request import (
810
openapi_request_parameters_validator,
@@ -13,8 +15,10 @@
1315
from openapi_core.validation.request import openapi_v30_request_validator
1416
from openapi_core.validation.request import openapi_v31_request_validator
1517
from openapi_core.validation.response import V3ResponseValidator
18+
from openapi_core.validation.response import V3WebhookResponseValidator
1619
from openapi_core.validation.response import V30ResponseValidator
1720
from openapi_core.validation.response import V31ResponseValidator
21+
from openapi_core.validation.response import V31WebhookResponseValidator
1822
from openapi_core.validation.response import openapi_response_data_validator
1923
from openapi_core.validation.response import openapi_response_headers_validator
2024
from openapi_core.validation.response import openapi_response_validator
@@ -36,10 +40,14 @@
3640
"validate_response",
3741
"V30RequestValidator",
3842
"V31RequestValidator",
39-
"V3RequestValidator",
4043
"V30ResponseValidator",
4144
"V31ResponseValidator",
45+
"V31WebhookRequestValidator",
46+
"V31WebhookResponseValidator",
47+
"V3RequestValidator",
4248
"V3ResponseValidator",
49+
"V3WebhookRequestValidator",
50+
"V3WebhookResponseValidator",
4351
"openapi_v3_request_validator",
4452
"openapi_v30_request_validator",
4553
"openapi_v31_request_validator",
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
from openapi_core.contrib.requests.requests import RequestsOpenAPIRequest
2+
from openapi_core.contrib.requests.requests import (
3+
RequestsOpenAPIWebhookRequest,
4+
)
25
from openapi_core.contrib.requests.responses import RequestsOpenAPIResponse
36

47
__all__ = [
58
"RequestsOpenAPIRequest",
69
"RequestsOpenAPIResponse",
10+
"RequestsOpenAPIWebhookRequest",
711
]

‎openapi_core/contrib/requests/requests.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
class RequestsOpenAPIRequest:
1818
"""
19-
Converts a requests request to an OpenAPI one
19+
Converts a requests request to an OpenAPI request
2020
2121
Internally converts to a `PreparedRequest` first to parse the exact
2222
payload being sent
@@ -76,3 +76,16 @@ def mimetype(self) -> str:
7676
self.request.headers.get("Content-Type")
7777
or self.request.headers.get("Accept")
7878
)
79+
80+
81+
class RequestsOpenAPIWebhookRequest(RequestsOpenAPIRequest):
82+
"""
83+
Converts a requests request to an OpenAPI Webhook request
84+
85+
Internally converts to a `PreparedRequest` first to parse the exact
86+
payload being sent
87+
"""
88+
89+
def __init__(self, request: Union[Request, PreparedRequest], name: str):
90+
super().__init__(request)
91+
self.name = name

‎openapi_core/security/providers.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,37 @@
33

44
from openapi_core.security.exceptions import SecurityError
55
from openapi_core.spec import Spec
6-
from openapi_core.validation.request.protocols import Request
6+
from openapi_core.validation.request.datatypes import RequestParameters
77

88

99
class BaseProvider:
1010
def __init__(self, scheme: Spec):
1111
self.scheme = scheme
1212

13-
def __call__(self, request: Request) -> Any:
13+
def __call__(self, parameters: RequestParameters) -> Any:
1414
raise NotImplementedError
1515

1616

1717
class UnsupportedProvider(BaseProvider):
18-
def __call__(self, request: Request) -> Any:
18+
def __call__(self, parameters: RequestParameters) -> Any:
1919
warnings.warn("Unsupported scheme type")
2020

2121

2222
class ApiKeyProvider(BaseProvider):
23-
def __call__(self, request: Request) -> Any:
23+
def __call__(self, parameters: RequestParameters) -> Any:
2424
name = self.scheme["name"]
2525
location = self.scheme["in"]
26-
source = getattr(request.parameters, location)
26+
source = getattr(parameters, location)
2727
if name not in source:
2828
raise SecurityError("Missing api key parameter.")
2929
return source[name]
3030

3131

3232
class HttpProvider(BaseProvider):
33-
def __call__(self, request: Request) -> Any:
34-
if "Authorization" not in request.parameters.header:
33+
def __call__(self, parameters: RequestParameters) -> Any:
34+
if "Authorization" not in parameters.header:
3535
raise SecurityError("Missing authorization header.")
36-
auth_header = request.parameters.header["Authorization"]
36+
auth_header = parameters.header["Authorization"]
3737
try:
3838
auth_type, encoded_credentials = auth_header.split(" ", 1)
3939
except ValueError:

‎openapi_core/templating/paths/datatypes.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
from collections import namedtuple
33

44
Path = namedtuple("Path", ["path", "path_result"])
5-
OperationPath = namedtuple(
6-
"OperationPath", ["path", "operation", "path_result"]
5+
PathOperation = namedtuple(
6+
"PathOperation", ["path", "operation", "path_result"]
77
)
8-
ServerOperationPath = namedtuple(
9-
"ServerOperationPath",
8+
PathOperationServer = namedtuple(
9+
"PathOperationServer",
1010
["path", "operation", "server", "path_result", "server_result"],
1111
)

0 commit comments

Comments
 (0)
Please sign in to comment.