I was wondering if there is planned support for adding the common errors that DRF returns for common errors as documented here:
http://www.django-rest-framework.org/api-guide/exceptions/#generic-error-views
The one I'm most in interested in is ValidationError.
Thank you for your wonderful work!
This would be a good addition but I don't plan on doing much work on new features in the near future.
Pull requests are always welcome, of course.
You could implement this as follows:
class ErrorResponseAutoSchema(SwaggerAutoSchema):
def get_generic_error_schema(self):
return openapi.Schema(
'Generic API Error',
type=openapi.TYPE_OBJECT,
properties={
'detail': openapi.Schema(type=openapi.TYPE_STRING, description='Error details'),
'code': openapi.Schema(type=openapi.TYPE_STRING, description='Error code'),
},
required=['detail']
)
def get_validation_error_schema(self):
return openapi.Schema(
'Validation Error',
type=openapi.TYPE_OBJECT,
properties={
api_settings.NON_FIELD_ERRORS_KEY: openapi.Schema(
description='List of validation errors not related to any field',
type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_STRING)
),
},
additional_properties=openapi.Schema(
description='A list of error messages for each field that triggered a validation error',
type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_STRING)
)
)
def get_response_serializers(self):
responses = super().get_response_serializers()
definitions = self.components.with_scope(openapi.SCHEMA_DEFINITIONS) # type: openapi.ReferenceResolver
definitions.setdefault('ValidationError', self.get_validation_error_schema)
definitions.setdefault('APIException', self.get_generic_error_schema)
if self.get_request_serializer() or self.get_query_serializer():
responses.setdefault(exceptions.ValidationError.status_code, openapi.Response(
description=force_real_str(exceptions.ValidationError.default_detail),
schema=openapi.SchemaRef(definitions, 'ValidationError')
))
security = self.get_security()
if security is None or len(security) > 0:
responses.setdefault(exceptions.AuthenticationFailed.status_code, openapi.Response(
description="Authentication credentials were invalid, absent or insufficient.",
schema=openapi.SchemaRef(definitions, 'GenericError')
))
if not is_list_view(self.path, self.method, self.view):
responses.setdefault(exceptions.PermissionDenied.status_code, openapi.Response(
description="Permission denied.",
schema=openapi.SchemaRef(definitions, 'APIException')
))
responses.setdefault(exceptions.NotFound.status_code, openapi.Response(
description="Object does not exist or caller has insufficient permissions to access it.",
schema=openapi.SchemaRef(definitions, 'APIException')
))
return responses
For now I'd like to avoid including this directly in the code base.
I have adapted this slightly to match the exact output of DRF
from drf_yasg import openapi
from drf_yasg.inspectors.view import SwaggerAutoSchema
from drf_yasg.utils import force_real_str, is_list_view
from rest_framework import exceptions
from rest_framework.settings import api_settings
from rest_framework import status
class ErrorResponseAutoSchema(SwaggerAutoSchema):
def get_generic_error_schema(self):
return openapi.Schema(
'Generic API Error',
type=openapi.TYPE_OBJECT,
properties={
'errors': openapi.Schema(type=openapi.TYPE_OBJECT, properties={
'detail': openapi.Schema(type=openapi.TYPE_STRING, description='Error details'),
'code': openapi.Schema(type=openapi.TYPE_STRING, description='Error code'),
})
},
required=['detail']
)
def get_validation_error_schema(self):
return openapi.Schema(
'Validation Error',
type=openapi.TYPE_OBJECT,
properties={
'errors': openapi.Schema(
type=openapi.TYPE_OBJECT,
description='error messages for each field that triggered a validation error',
additional_properties=openapi.Schema(
description='A list of error messages for the field',
type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_STRING)
)),
api_settings.NON_FIELD_ERRORS_KEY: openapi.Schema(
description='List of validation errors not related to any field',
type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_STRING)
),
}
)
def get_response_serializers(self):
responses = super().get_response_serializers()
definitions = self.components.with_scope(
openapi.SCHEMA_DEFINITIONS) # type: openapi.ReferenceResolver
definitions.setdefault('GenericError', self.get_generic_error_schema)
definitions.setdefault('ValidationError', self.get_validation_error_schema)
definitions.setdefault('APIException', self.get_generic_error_schema)
if self.get_request_serializer() or self.get_query_serializer():
responses.setdefault(exceptions.ValidationError.status_code, openapi.Response(
description=force_real_str(exceptions.ValidationError.default_detail),
schema=openapi.SchemaRef(definitions, 'ValidationError')
))
security = self.get_security()
if security is None or len(security) > 0:
# Note: 401 error codes are coerced into 403 see rest_framework/views.py:433:handle_exception
# This is b/c the API uses token auth which doesn't have WWW-Authenticate header
responses.setdefault(status.HTTP_403_FORBIDDEN, openapi.Response(
description="Authentication credentials were invalid, absent or insufficient.",
schema=openapi.SchemaRef(definitions, 'GenericError')
))
if not is_list_view(self.path, self.method, self.view):
responses.setdefault(exceptions.PermissionDenied.status_code, openapi.Response(
description="Permission denied.",
schema=openapi.SchemaRef(definitions, 'APIException')
))
responses.setdefault(exceptions.NotFound.status_code, openapi.Response(
description="Object does not exist or caller has insufficient permissions to access it.",
schema=openapi.SchemaRef(definitions, 'APIException')
))
return responses
It would be awesome to document the error responses you can get!
Thanks for the code. It helped much more, than the documentation.
How such a schema could be deduced from an error serializer? Any helpers for that out of the box?
Most helpful comment
I have adapted this slightly to match the exact output of DRF