diff --git a/README.rst b/README.rst index 079a867..23c4c66 100644 --- a/README.rst +++ b/README.rst @@ -126,7 +126,7 @@ In ``urls.py``: contact=openapi.Contact(email="contact@snippets.local"), license=openapi.License(name="BSD License"), ), - validators=['ssv', 'flex'], + validators=['flex', 'ssv'], public=True, permission_classes=(permissions.AllowAny,), ) @@ -267,7 +267,7 @@ caching the schema view in-memory, with some sane defaults: Given the numerous methods to manually customzie the generated schema, it makes sense to validate the result to ensure it still conforms to OpenAPI 2.0. To this end, validation is provided at the generation point using python swagger -libraries, and can be activated by passing :python:`validators=['ssv', 'flex']` to ``get_schema_view``; if the generated +libraries, and can be activated by passing :python:`validators=['flex', 'ssv']` to ``get_schema_view``; if the generated schema is not valid, a :python:`SwaggerValidationError` is raised by the handling codec. **Warning:** This internal validation can slow down your server. diff --git a/src/drf_yasg/codecs.py b/src/drf_yasg/codecs.py index 40a9e4c..ccbeb6b 100644 --- a/src/drf_yasg/codecs.py +++ b/src/drf_yasg/codecs.py @@ -12,22 +12,22 @@ from .app_settings import swagger_settings from .errors import SwaggerValidationError -def _validate_flex(spec, codec): +def _validate_flex(spec): from flex.core import parse as validate_flex from flex.exceptions import ValidationError try: validate_flex(spec) except ValidationError as ex: - raise_from(SwaggerValidationError(str(ex), 'flex', spec, codec), ex) + raise_from(SwaggerValidationError(str(ex)), ex) -def _validate_swagger_spec_validator(spec, codec): +def _validate_swagger_spec_validator(spec): from swagger_spec_validator.validator20 import validate_spec as validate_ssv from swagger_spec_validator.common import SwaggerValidationError as SSVErr try: validate_ssv(spec) except SSVErr as ex: - raise_from(SwaggerValidationError(str(ex), 'swagger_spec_validator', spec, codec), ex) + raise_from(SwaggerValidationError(str(ex)), ex) #: @@ -61,10 +61,17 @@ class _OpenAPICodec(object): raise TypeError('Expected a `openapi.Swagger` instance') spec = self.generate_swagger_object(document) + errors = {} for validator in self.validators: - # validate a deepcopy of the spec to prevent the validator from messing with it - # for example, swagger_spec_validator adds an x-scope property to all references - VALIDATORS[validator](copy.deepcopy(spec), self) + try: + # validate a deepcopy of the spec to prevent the validator from messing with it + # for example, swagger_spec_validator adds an x-scope property to all references + VALIDATORS[validator](copy.deepcopy(spec)) + except SwaggerValidationError as e: + errors[validator] = str(e) + + if errors: + raise SwaggerValidationError("spec validation failed", errors, spec, self) return force_bytes(self._dump_dict(spec)) def encode_error(self, err): diff --git a/src/drf_yasg/errors.py b/src/drf_yasg/errors.py index 745ec57..094995f 100644 --- a/src/drf_yasg/errors.py +++ b/src/drf_yasg/errors.py @@ -3,9 +3,9 @@ class SwaggerError(Exception): class SwaggerValidationError(SwaggerError): - def __init__(self, msg, validator_name, spec, source_codec, *args): + def __init__(self, msg, errors=None, spec=None, source_codec=None, *args): super(SwaggerValidationError, self).__init__(msg, *args) - self.validator_name = validator_name + self.errors = errors self.spec = spec self.source_codec = source_codec diff --git a/src/drf_yasg/middleware.py b/src/drf_yasg/middleware.py index 49f06dc..c25edee 100644 --- a/src/drf_yasg/middleware.py +++ b/src/drf_yasg/middleware.py @@ -13,7 +13,7 @@ class SwaggerExceptionMiddleware(object): def process_exception(self, request, exception): if isinstance(exception, SwaggerValidationError): - err = {'errors': {exception.validator_name: str(exception)}} + err = {'errors': exception.errors, 'message': str(exception)} codec = exception.source_codec if isinstance(codec, _OpenAPICodec): err = codec.encode_error(err) diff --git a/src/drf_yasg/renderers.py b/src/drf_yasg/renderers.py index acb2aa5..9f5b5ab 100644 --- a/src/drf_yasg/renderers.py +++ b/src/drf_yasg/renderers.py @@ -9,7 +9,7 @@ from .codecs import VALIDATORS, OpenAPICodecJson, OpenAPICodecYaml class _SpecRenderer(BaseRenderer): """Base class for text renderers. Handles encoding and validation.""" charset = None - validators = ['ssv', 'flex'] + validators = [] codec_class = None @classmethod diff --git a/src/drf_yasg/views.py b/src/drf_yasg/views.py index aba0d34..1ab1f7a 100644 --- a/src/drf_yasg/views.py +++ b/src/drf_yasg/views.py @@ -12,8 +12,9 @@ from rest_framework.views import APIView from .app_settings import swagger_settings from .generators import OpenAPISchemaGenerator -from .renderers import OpenAPIRenderer, ReDocRenderer, SwaggerJSONRenderer, SwaggerUIRenderer, SwaggerYAMLRenderer, \ - ReDocAlphaRenderer +from .renderers import ( + OpenAPIRenderer, ReDocAlphaRenderer, ReDocRenderer, SwaggerJSONRenderer, SwaggerUIRenderer, SwaggerYAMLRenderer +) SPEC_RENDERERS = (SwaggerYAMLRenderer, SwaggerJSONRenderer, OpenAPIRenderer) UI_RENDERERS = {