Skip to content

Validators refactor #457

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,20 @@ Alternatively you can download the code and install from the repository:
Usage
#####

Firstly create your specification object. By default, OpenAPI spec version is detected:
Firstly create your specification object.

.. code-block:: python

from openapi_core import Spec

spec = Spec.from_file_path('openapi.json')

Now you can use it to validate against requests and/or responses.

Request
*******

Now you can use it to validate against requests
Use ``validate_request`` function to validate request against a given spec.

.. code-block:: python

Expand All @@ -78,7 +80,7 @@ Now you can use it to validate against requests
# raise error if request is invalid
result = validate_request(request, spec=spec)

and unmarshal request data from validation result
Retrieve request data from validation result

.. code-block:: python

Expand All @@ -98,7 +100,7 @@ Request object should implement OpenAPI Request protocol (See `Integrations <htt
Response
********

You can also validate against responses
Use ``validate_response`` function to validate response against a given spec.

.. code-block:: python

Expand All @@ -121,16 +123,16 @@ Response object should implement OpenAPI Response protocol (See `Integrations <h

In order to explicitly validate a:

* OpenAPI 3.0 spec, import ``openapi_v30_request_validator`` or ``openapi_v30_response_validator``
* OpenAPI 3.1 spec, import ``openapi_v31_request_validator`` or ``openapi_v31_response_validator``
* OpenAPI 3.0 spec, import ``V30RequestValidator`` or ``V30ResponseValidator``
* OpenAPI 3.1 spec, import ``V31RequestValidator`` or ``V31ResponseValidator``

.. code:: python

from openapi_core import openapi_v31_response_validator
from openapi_core import V31ResponseValidator

result = validate_response(request, response, spec=spec, validator=openapi_v31_response_validator)
result = validate_response(request, response, spec=spec, cls=V31ResponseValidator)

You can also explicitly import ``openapi_v3_request_validator`` or ``openapi_v3_response_validator`` which is a shortcut to the latest v3 release.
You can also explicitly import ``V3RequestValidator`` or ``V3ResponseValidator`` which is a shortcut to the latest v3 release.

Related projects
################
Expand Down
17 changes: 10 additions & 7 deletions docs/customizations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ Pass custom defined media type deserializers dictionary with supported mimetypes
.. code-block:: python

from openapi_core.deserializing.media_types.factories import MediaTypeDeserializersFactory
from openapi_core.unmarshalling.schemas import oas30_response_schema_unmarshallers_factory

def protobuf_deserializer(message):
feature = route_guide_pb2.Feature()
Expand All @@ -36,13 +35,13 @@ Pass custom defined media type deserializers dictionary with supported mimetypes
custom_deserializers=custom_media_type_deserializers,
)

validator = ResponseValidator(
oas30_response_schema_unmarshallers_factory,
result = validate_response(
request, response,
spec=spec,
cls=V30ResponseValidator,
media_type_deserializers_factory=media_type_deserializers_factory,
)

result = validator.validate(spec, request, response)

Formats
-------

Expand Down Expand Up @@ -75,7 +74,11 @@ Here's how you could add support for a ``usdate`` format that handles dates of t
custom_formatters=custom_formatters,
context=UnmarshalContext.RESPONSE,
)
validator = ResponseValidator(schema_unmarshallers_factory)

result = validator.validate(spec, request, response)
result = validate_response(
request, response,
spec=spec,
cls=ResponseValidator,
schema_unmarshallers_factory=schema_unmarshallers_factory,
)

13 changes: 6 additions & 7 deletions docs/usage.rst
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
Usage
=====

Firstly create your specification object. By default, OpenAPI spec version is detected:
Firstly create your specification object.

.. code-block:: python

from openapi_core import Spec

spec = Spec.from_file_path('openapi.json')

Now you can use it to validate against requests and/or responses.

Request
-------

Now you can use it to validate against requests
Use ``validate_request`` function to validate request against a given spec. By default, OpenAPI spec version is detected:

.. code-block:: python

Expand All @@ -22,7 +23,7 @@ Now you can use it to validate against requests
# raise error if request is invalid
result = validate_request(request, spec=spec)

and unmarshal request data from validation result
Retrieve validated and unmarshalled request data from validation result

.. code-block:: python

Expand All @@ -42,7 +43,7 @@ Request object should implement OpenAPI Request protocol (See :doc:`integrations
Response
--------

You can also validate against responses
Use ``validate_response`` function to validate response against a given spec. By default, OpenAPI spec version is detected:

.. code-block:: python

Expand All @@ -51,7 +52,7 @@ You can also validate against responses
# raise error if response is invalid
result = validate_response(request, response, spec=spec)

and unmarshal response data from validation result
Retrieve validated and unmarshalled response data from validation result

.. code-block:: python

Expand Down Expand Up @@ -89,8 +90,6 @@ you can access your security data the following:

.. code-block:: python

result = validator.validate(request)

# get basic auth decoded credentials
result.security['BasicAuth']

Expand Down
12 changes: 12 additions & 0 deletions openapi_core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
"""OpenAPI core module"""
from openapi_core.spec import Spec
from openapi_core.validation.request import V3RequestValidator
from openapi_core.validation.request import V30RequestValidator
from openapi_core.validation.request import V31RequestValidator
from openapi_core.validation.request import openapi_request_body_validator
from openapi_core.validation.request import (
openapi_request_parameters_validator,
Expand All @@ -9,6 +12,9 @@
from openapi_core.validation.request import openapi_v3_request_validator
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 V30ResponseValidator
from openapi_core.validation.response import V31ResponseValidator
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 @@ -28,6 +34,12 @@
"Spec",
"validate_request",
"validate_response",
"V30RequestValidator",
"V31RequestValidator",
"V3RequestValidator",
"V30ResponseValidator",
"V31ResponseValidator",
"V3ResponseValidator",
"openapi_v3_request_validator",
"openapi_v30_request_validator",
"openapi_v31_request_validator",
Expand Down
14 changes: 3 additions & 11 deletions openapi_core/contrib/django/middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,8 @@
from openapi_core.contrib.django.requests import DjangoOpenAPIRequest
from openapi_core.contrib.django.responses import DjangoOpenAPIResponse
from openapi_core.validation.processors import OpenAPIProcessor
from openapi_core.validation.request import openapi_request_validator
from openapi_core.validation.request.datatypes import RequestValidationResult
from openapi_core.validation.request.protocols import Request
from openapi_core.validation.response import openapi_response_validator
from openapi_core.validation.response.datatypes import ResponseValidationResult
from openapi_core.validation.response.protocols import Response


class DjangoOpenAPIMiddleware:
Expand All @@ -31,15 +27,11 @@ def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
if not hasattr(settings, "OPENAPI_SPEC"):
raise ImproperlyConfigured("OPENAPI_SPEC not defined in settings")

self.validation_processor = OpenAPIProcessor(
openapi_request_validator, openapi_response_validator
)
self.validation_processor = OpenAPIProcessor(settings.OPENAPI_SPEC)

def __call__(self, request: HttpRequest) -> HttpResponse:
openapi_request = self._get_openapi_request(request)
req_result = self.validation_processor.process_request(
settings.OPENAPI_SPEC, openapi_request
)
req_result = self.validation_processor.process_request(openapi_request)
if req_result.errors:
response = self._handle_request_errors(req_result, request)
else:
Expand All @@ -48,7 +40,7 @@ def __call__(self, request: HttpRequest) -> HttpResponse:

openapi_response = self._get_openapi_response(response)
resp_result = self.validation_processor.process_response(
settings.OPENAPI_SPEC, openapi_request, openapi_response
openapi_request, openapi_response
)
if resp_result.errors:
return self._handle_response_errors(resp_result, request, response)
Expand Down
48 changes: 18 additions & 30 deletions openapi_core/contrib/falcon/middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
from openapi_core.contrib.falcon.responses import FalconOpenAPIResponse
from openapi_core.spec import Spec
from openapi_core.validation.processors import OpenAPIProcessor
from openapi_core.validation.request import openapi_request_validator
from openapi_core.validation.request.datatypes import RequestValidationResult
from openapi_core.validation.response import openapi_response_validator
from openapi_core.validation.request.protocols import RequestValidator
from openapi_core.validation.response.datatypes import ResponseValidationResult
from openapi_core.validation.response.protocols import ResponseValidator


class FalconOpenAPIMiddleware:
class FalconOpenAPIMiddleware(OpenAPIProcessor):

request_class = FalconOpenAPIRequest
response_class = FalconOpenAPIResponse
Expand All @@ -26,13 +26,17 @@ class FalconOpenAPIMiddleware:
def __init__(
self,
spec: Spec,
validation_processor: OpenAPIProcessor,
request_validator_cls: Optional[Type[RequestValidator]] = None,
response_validator_cls: Optional[Type[ResponseValidator]] = None,
request_class: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
response_class: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse,
errors_handler: Optional[FalconOpenAPIErrorsHandler] = None,
):
self.spec = spec
self.validation_processor = validation_processor
super().__init__(
spec,
request_validator_cls=request_validator_cls,
response_validator_cls=response_validator_cls,
)
self.request_class = request_class or self.request_class
self.response_class = response_class or self.response_class
self.errors_handler = errors_handler or self.errors_handler
Expand All @@ -41,33 +45,33 @@ def __init__(
def from_spec(
cls,
spec: Spec,
request_validator_cls: Optional[Type[RequestValidator]] = None,
response_validator_cls: Optional[Type[ResponseValidator]] = None,
request_class: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
response_class: Type[FalconOpenAPIResponse] = FalconOpenAPIResponse,
errors_handler: Optional[FalconOpenAPIErrorsHandler] = None,
) -> "FalconOpenAPIMiddleware":
validation_processor = OpenAPIProcessor(
openapi_request_validator, openapi_response_validator
)
return cls(
spec,
validation_processor,
request_validator_cls=request_validator_cls,
response_validator_cls=response_validator_cls,
request_class=request_class,
response_class=response_class,
errors_handler=errors_handler,
)

def process_request(self, req: Request, resp: Response) -> None:
def process_request(self, req: Request, resp: Response) -> None: # type: ignore
openapi_req = self._get_openapi_request(req)
req.context.openapi = self._process_openapi_request(openapi_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_response(
def process_response( # type: ignore
self, req: Request, resp: Response, resource: Any, req_succeeded: bool
) -> None:
openapi_req = self._get_openapi_request(req)
openapi_resp = self._get_openapi_response(resp)
resp.context.openapi = self._process_openapi_response(
resp.context.openapi = super().process_response(
openapi_req, openapi_resp
)
if resp.context.openapi.errors:
Expand Down Expand Up @@ -98,19 +102,3 @@ def _get_openapi_response(
self, response: Response
) -> FalconOpenAPIResponse:
return self.response_class(response)

def _process_openapi_request(
self, openapi_request: FalconOpenAPIRequest
) -> RequestValidationResult:
return self.validation_processor.process_request(
self.spec, openapi_request
)

def _process_openapi_response(
self,
opneapi_request: FalconOpenAPIRequest,
openapi_response: FalconOpenAPIResponse,
) -> ResponseValidationResult:
return self.validation_processor.process_response(
self.spec, opneapi_request, openapi_response
)
Loading