Skip to content

Commit

Permalink
Webhooks support
Browse files Browse the repository at this point in the history
  • Loading branch information
p1c2u committed Jan 20, 2023
1 parent e576212 commit 2535eeb
Show file tree
Hide file tree
Showing 26 changed files with 1,099 additions and 343 deletions.
28 changes: 22 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ Use ``validate_request`` function to validate request against a given spec.
# raise error if request is invalid
result = validate_request(request, spec=spec)
Request object should implement OpenAPI Request protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).

Use the same function to validate webhook request against a given spec.

.. code-block:: python
# raise error if request is invalid
result = validate_request(webhook_request, spec=spec)
Webhook request object should implement OpenAPI WebhookRequest protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).

Retrieve request data from validation result

.. code-block:: python
Expand All @@ -95,8 +106,6 @@ Retrieve request data from validation result
# get security data
validated_security = result.security
Request object should implement OpenAPI Request protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).

Response
********

Expand All @@ -109,7 +118,16 @@ Use ``validate_response`` function to validate response against a given spec.
# raise error if response is invalid
result = validate_response(request, response, spec=spec)
and unmarshal response data from validation result
Response object should implement OpenAPI Response protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).

Use the same function to validate response from webhook request against a given spec.

.. code-block:: python
# raise error if request is invalid
result = validate_response(webhook_request, response, spec=spec)
Retrieve response data from validation result

.. code-block:: python
Expand All @@ -119,12 +137,10 @@ and unmarshal response data from validation result
# get data
validated_data = result.data
Response object should implement OpenAPI Response protocol (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).

In order to explicitly validate a:

* OpenAPI 3.0 spec, import ``V30RequestValidator`` or ``V30ResponseValidator``
* OpenAPI 3.1 spec, import ``V31RequestValidator`` or ``V31ResponseValidator``
* OpenAPI 3.1 spec, import ``V31RequestValidator`` or ``V31ResponseValidator`` or ``V31WebhookRequestValidator`` or ``V31WebhookResponseValidator``

.. code:: python
Expand Down
11 changes: 11 additions & 0 deletions docs/integrations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,17 @@ You can use ``RequestsOpenAPIResponse`` as a Requests response factory:
result = validate_response(openapi_request, openapi_response, spec=spec)
You can use ``RequestsOpenAPIWebhookRequest`` as a Requests webhook request factory:

.. code-block:: python
from openapi_core import validate_request
from openapi_core.contrib.requests import RequestsOpenAPIWebhookRequest
openapi_webhook_request = RequestsOpenAPIWebhookRequest(requests_request, "my_webhook")
result = validate_request(openapi_webhook_request, spec=spec)
Starlette
---------

Expand Down
24 changes: 20 additions & 4 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ Use ``validate_request`` function to validate request against a given spec. By d
# raise error if request is invalid
result = validate_request(request, spec=spec)
Request object should implement OpenAPI Request protocol (See :doc:`integrations`).

Use the same function to validate webhook request against a given spec.

.. code-block:: python
# raise error if request is invalid
result = validate_request(webhook_request, spec=spec)
Webhook request object should implement OpenAPI WebhookRequest protocol (See :doc:`integrations`).

Retrieve validated and unmarshalled request data from validation result

.. code-block:: python
Expand All @@ -38,8 +49,6 @@ Retrieve validated and unmarshalled request data from validation result
# get security data
validated_security = result.security
Request object should implement OpenAPI Request protocol (See :doc:`integrations`).

Response
--------

Expand All @@ -52,6 +61,15 @@ Use ``validate_response`` function to validate response against a given spec. By
# raise error if response is invalid
result = validate_response(request, response, spec=spec)
Response object should implement OpenAPI Response protocol (See :doc:`integrations`).

Use the same function to validate response from webhook request against a given spec.

.. code-block:: python
# raise error if request is invalid
result = validate_response(webhook_request, response, spec=spec)
Retrieve validated and unmarshalled response data from validation result

.. code-block:: python
Expand All @@ -62,8 +80,6 @@ Retrieve validated and unmarshalled response data from validation result
# get data
validated_data = result.data
Response object should implement OpenAPI Response protocol (See :doc:`integrations`).

Security
--------

Expand Down
10 changes: 9 additions & 1 deletion openapi_core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""OpenAPI core module"""
from openapi_core.spec import Spec
from openapi_core.validation.request import V3RequestValidator
from openapi_core.validation.request import V3WebhookRequestValidator
from openapi_core.validation.request import V30RequestValidator
from openapi_core.validation.request import V31RequestValidator
from openapi_core.validation.request import V31WebhookRequestValidator
from openapi_core.validation.request import openapi_request_body_validator
from openapi_core.validation.request import (
openapi_request_parameters_validator,
Expand All @@ -13,8 +15,10 @@
from openapi_core.validation.request import openapi_v30_request_validator
from openapi_core.validation.request import openapi_v31_request_validator
from openapi_core.validation.response import V3ResponseValidator
from openapi_core.validation.response import V3WebhookResponseValidator
from openapi_core.validation.response import V30ResponseValidator
from openapi_core.validation.response import V31ResponseValidator
from openapi_core.validation.response import V31WebhookResponseValidator
from openapi_core.validation.response import openapi_response_data_validator
from openapi_core.validation.response import openapi_response_headers_validator
from openapi_core.validation.response import openapi_response_validator
Expand All @@ -36,10 +40,14 @@
"validate_response",
"V30RequestValidator",
"V31RequestValidator",
"V3RequestValidator",
"V30ResponseValidator",
"V31ResponseValidator",
"V31WebhookRequestValidator",
"V31WebhookResponseValidator",
"V3RequestValidator",
"V3ResponseValidator",
"V3WebhookRequestValidator",
"V3WebhookResponseValidator",
"openapi_v3_request_validator",
"openapi_v30_request_validator",
"openapi_v31_request_validator",
Expand Down
4 changes: 4 additions & 0 deletions openapi_core/contrib/requests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from openapi_core.contrib.requests.requests import RequestsOpenAPIRequest
from openapi_core.contrib.requests.requests import (
RequestsOpenAPIWebhookRequest,
)
from openapi_core.contrib.requests.responses import RequestsOpenAPIResponse

__all__ = [
"RequestsOpenAPIRequest",
"RequestsOpenAPIResponse",
"RequestsOpenAPIWebhookRequest",
]
15 changes: 14 additions & 1 deletion openapi_core/contrib/requests/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

class RequestsOpenAPIRequest:
"""
Converts a requests request to an OpenAPI one
Converts a requests request to an OpenAPI request
Internally converts to a `PreparedRequest` first to parse the exact
payload being sent
Expand Down Expand Up @@ -76,3 +76,16 @@ def mimetype(self) -> str:
self.request.headers.get("Content-Type")
or self.request.headers.get("Accept")
)


class RequestsOpenAPIWebhookRequest(RequestsOpenAPIRequest):
"""
Converts a requests request to an OpenAPI Webhook request
Internally converts to a `PreparedRequest` first to parse the exact
payload being sent
"""

def __init__(self, request: Union[Request, PreparedRequest], name: str):
super().__init__(request)
self.name = name
16 changes: 8 additions & 8 deletions openapi_core/security/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,37 @@

from openapi_core.security.exceptions import SecurityError
from openapi_core.spec import Spec
from openapi_core.validation.request.protocols import Request
from openapi_core.validation.request.datatypes import RequestParameters


class BaseProvider:
def __init__(self, scheme: Spec):
self.scheme = scheme

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


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


class ApiKeyProvider(BaseProvider):
def __call__(self, request: Request) -> Any:
def __call__(self, parameters: RequestParameters) -> Any:
name = self.scheme["name"]
location = self.scheme["in"]
source = getattr(request.parameters, location)
source = getattr(parameters, location)
if name not in source:
raise SecurityError("Missing api key parameter.")
return source[name]


class HttpProvider(BaseProvider):
def __call__(self, request: Request) -> Any:
if "Authorization" not in request.parameters.header:
def __call__(self, parameters: RequestParameters) -> Any:
if "Authorization" not in parameters.header:
raise SecurityError("Missing authorization header.")
auth_header = request.parameters.header["Authorization"]
auth_header = parameters.header["Authorization"]
try:
auth_type, encoded_credentials = auth_header.split(" ", 1)
except ValueError:
Expand Down
8 changes: 4 additions & 4 deletions openapi_core/templating/paths/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from collections import namedtuple

Path = namedtuple("Path", ["path", "path_result"])
OperationPath = namedtuple(
"OperationPath", ["path", "operation", "path_result"]
PathOperation = namedtuple(
"PathOperation", ["path", "operation", "path_result"]
)
ServerOperationPath = namedtuple(
"ServerOperationPath",
PathOperationServer = namedtuple(
"PathOperationServer",
["path", "operation", "server", "path_result", "server_result"],
)
Loading

0 comments on commit 2535eeb

Please sign in to comment.