Improve validator error handling
parent
c225f66fb7
commit
57d77cc48a
|
|
@ -126,7 +126,7 @@ In ``urls.py``:
|
||||||
contact=openapi.Contact(email="contact@snippets.local"),
|
contact=openapi.Contact(email="contact@snippets.local"),
|
||||||
license=openapi.License(name="BSD License"),
|
license=openapi.License(name="BSD License"),
|
||||||
),
|
),
|
||||||
validators=['ssv', 'flex'],
|
validators=['flex', 'ssv'],
|
||||||
public=True,
|
public=True,
|
||||||
permission_classes=(permissions.AllowAny,),
|
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
|
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
|
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.
|
schema is not valid, a :python:`SwaggerValidationError` is raised by the handling codec.
|
||||||
|
|
||||||
**Warning:** This internal validation can slow down your server.
|
**Warning:** This internal validation can slow down your server.
|
||||||
|
|
|
||||||
|
|
@ -12,22 +12,22 @@ from .app_settings import swagger_settings
|
||||||
from .errors import SwaggerValidationError
|
from .errors import SwaggerValidationError
|
||||||
|
|
||||||
|
|
||||||
def _validate_flex(spec, codec):
|
def _validate_flex(spec):
|
||||||
from flex.core import parse as validate_flex
|
from flex.core import parse as validate_flex
|
||||||
from flex.exceptions import ValidationError
|
from flex.exceptions import ValidationError
|
||||||
try:
|
try:
|
||||||
validate_flex(spec)
|
validate_flex(spec)
|
||||||
except ValidationError as ex:
|
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.validator20 import validate_spec as validate_ssv
|
||||||
from swagger_spec_validator.common import SwaggerValidationError as SSVErr
|
from swagger_spec_validator.common import SwaggerValidationError as SSVErr
|
||||||
try:
|
try:
|
||||||
validate_ssv(spec)
|
validate_ssv(spec)
|
||||||
except SSVErr as ex:
|
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')
|
raise TypeError('Expected a `openapi.Swagger` instance')
|
||||||
|
|
||||||
spec = self.generate_swagger_object(document)
|
spec = self.generate_swagger_object(document)
|
||||||
|
errors = {}
|
||||||
for validator in self.validators:
|
for validator in self.validators:
|
||||||
# validate a deepcopy of the spec to prevent the validator from messing with it
|
try:
|
||||||
# for example, swagger_spec_validator adds an x-scope property to all references
|
# validate a deepcopy of the spec to prevent the validator from messing with it
|
||||||
VALIDATORS[validator](copy.deepcopy(spec), self)
|
# 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))
|
return force_bytes(self._dump_dict(spec))
|
||||||
|
|
||||||
def encode_error(self, err):
|
def encode_error(self, err):
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ class SwaggerError(Exception):
|
||||||
|
|
||||||
|
|
||||||
class SwaggerValidationError(SwaggerError):
|
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)
|
super(SwaggerValidationError, self).__init__(msg, *args)
|
||||||
self.validator_name = validator_name
|
self.errors = errors
|
||||||
self.spec = spec
|
self.spec = spec
|
||||||
self.source_codec = source_codec
|
self.source_codec = source_codec
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class SwaggerExceptionMiddleware(object):
|
||||||
|
|
||||||
def process_exception(self, request, exception):
|
def process_exception(self, request, exception):
|
||||||
if isinstance(exception, SwaggerValidationError):
|
if isinstance(exception, SwaggerValidationError):
|
||||||
err = {'errors': {exception.validator_name: str(exception)}}
|
err = {'errors': exception.errors, 'message': str(exception)}
|
||||||
codec = exception.source_codec
|
codec = exception.source_codec
|
||||||
if isinstance(codec, _OpenAPICodec):
|
if isinstance(codec, _OpenAPICodec):
|
||||||
err = codec.encode_error(err)
|
err = codec.encode_error(err)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ from .codecs import VALIDATORS, OpenAPICodecJson, OpenAPICodecYaml
|
||||||
class _SpecRenderer(BaseRenderer):
|
class _SpecRenderer(BaseRenderer):
|
||||||
"""Base class for text renderers. Handles encoding and validation."""
|
"""Base class for text renderers. Handles encoding and validation."""
|
||||||
charset = None
|
charset = None
|
||||||
validators = ['ssv', 'flex']
|
validators = []
|
||||||
codec_class = None
|
codec_class = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,9 @@ from rest_framework.views import APIView
|
||||||
|
|
||||||
from .app_settings import swagger_settings
|
from .app_settings import swagger_settings
|
||||||
from .generators import OpenAPISchemaGenerator
|
from .generators import OpenAPISchemaGenerator
|
||||||
from .renderers import OpenAPIRenderer, ReDocRenderer, SwaggerJSONRenderer, SwaggerUIRenderer, SwaggerYAMLRenderer, \
|
from .renderers import (
|
||||||
ReDocAlphaRenderer
|
OpenAPIRenderer, ReDocAlphaRenderer, ReDocRenderer, SwaggerJSONRenderer, SwaggerUIRenderer, SwaggerYAMLRenderer
|
||||||
|
)
|
||||||
|
|
||||||
SPEC_RENDERERS = (SwaggerYAMLRenderer, SwaggerJSONRenderer, OpenAPIRenderer)
|
SPEC_RENDERERS = (SwaggerYAMLRenderer, SwaggerJSONRenderer, OpenAPIRenderer)
|
||||||
UI_RENDERERS = {
|
UI_RENDERERS = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue