|
| 1 | +from drf_yasg import openapi |
| 2 | +from drf_yasg.inspectors.view import SwaggerAutoSchema |
| 3 | +from drf_yasg.utils import force_real_str, is_list_view |
| 4 | +from rest_framework import exceptions |
| 5 | +from rest_framework.settings import api_settings |
| 6 | +from rest_framework import status |
| 7 | + |
| 8 | + |
| 9 | +# Copied from https://github.com/axnsan12/drf-yasg/issues/224#issuecomment-449646157 by axnsan12 |
| 10 | + |
| 11 | +class ErrorResponseAutoSchema(SwaggerAutoSchema): |
| 12 | + def get_generic_error_schema(self): |
| 13 | + return openapi.Schema( |
| 14 | + 'Generic API Error', |
| 15 | + type=openapi.TYPE_OBJECT, |
| 16 | + properties={ |
| 17 | + 'detail': openapi.Schema(type=openapi.TYPE_STRING, description='Error details'), |
| 18 | + }, |
| 19 | + required=['detail'] |
| 20 | + ) |
| 21 | + |
| 22 | + def get_validation_error_schema(self): |
| 23 | + return openapi.Schema( |
| 24 | + 'Validation Error', |
| 25 | + type=openapi.TYPE_OBJECT, |
| 26 | + # properties={ |
| 27 | + # 'errors': openapi.Schema( |
| 28 | + # type=openapi.TYPE_OBJECT, |
| 29 | + # description='error messages for each field that triggered a validation error', |
| 30 | + # additional_properties=openapi.Schema( |
| 31 | + # description='A list of error messages for the field', |
| 32 | + # type=openapi.TYPE_ARRAY, items=openapi.Schema( |
| 33 | + # type=openapi.TYPE_STRING) |
| 34 | + # )), |
| 35 | + # api_settings.NON_FIELD_ERRORS_KEY: openapi.Schema( |
| 36 | + # description='List of validation errors not related to any field', |
| 37 | + # type=openapi.TYPE_ARRAY, items=openapi.Schema( |
| 38 | + # type=openapi.TYPE_STRING) |
| 39 | + # ), |
| 40 | + # } |
| 41 | + ) |
| 42 | + |
| 43 | + def get_response_serializers(self): |
| 44 | + responses = super().get_response_serializers() |
| 45 | + definitions = self.components.with_scope( |
| 46 | + openapi.SCHEMA_DEFINITIONS) # type: openapi.ReferenceResolver |
| 47 | + |
| 48 | + definitions.setdefault('GenericError', self.get_generic_error_schema) |
| 49 | + definitions.setdefault( |
| 50 | + 'ValidationError', self.get_validation_error_schema) |
| 51 | + definitions.setdefault('APIException', self.get_generic_error_schema) |
| 52 | + |
| 53 | + if self.get_request_serializer() or self.get_query_serializer(): |
| 54 | + responses.setdefault(exceptions.ValidationError.status_code, openapi.Response( |
| 55 | + description=force_real_str( |
| 56 | + exceptions.ValidationError.default_detail), |
| 57 | + schema=openapi.SchemaRef(definitions, 'ValidationError') |
| 58 | + )) |
| 59 | + |
| 60 | + security = self.get_security() |
| 61 | + if security is None or len(security) > 0: |
| 62 | + # Note: 401 error codes are coerced into 403 see rest_framework/views.py:433:handle_exception |
| 63 | + # This is b/c the API uses token auth which doesn't have WWW-Authenticate header |
| 64 | + responses.setdefault(status.HTTP_403_FORBIDDEN, openapi.Response( |
| 65 | + description="Authentication credentials were invalid, absent or insufficient.", |
| 66 | + schema=openapi.SchemaRef(definitions, 'GenericError') |
| 67 | + )) |
| 68 | + if not is_list_view(self.path, self.method, self.view): |
| 69 | + responses.setdefault(exceptions.PermissionDenied.status_code, openapi.Response( |
| 70 | + description="Permission denied.", |
| 71 | + schema=openapi.SchemaRef(definitions, 'APIException') |
| 72 | + )) |
| 73 | + responses.setdefault(exceptions.NotFound.status_code, openapi.Response( |
| 74 | + description="Object does not exist or caller has insufficient permissions to access it.", |
| 75 | + schema=openapi.SchemaRef(definitions, 'APIException') |
| 76 | + )) |
| 77 | + |
| 78 | + return responses |
0 commit comments