Skip to content

Commit e3f781b

Browse files
authored
Merge pull request #75 from ghazi-git/add-example-only-when-corresponding-status-code-is-allowed
add-example-only-when-corresponding-status-code-is-allowed
2 parents 8f4b383 + dcb292d commit e3f781b

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

docs/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1111
### Fixed
1212
- enforce support of only drf-spectacular 0.27 and newer in pyproject.toml
1313
- ensure examples from `@extend_schema_serializer` are not ignored when adding error response examples
14+
- show default error response examples only when the corresponding status code is allowed
1415

1516
## [0.13.0] - 2024-02-28
1617
### Changed

drf_standardized_errors/openapi.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from drf_spectacular.drainage import warn
66
from drf_spectacular.extensions import OpenApiFilterExtension
77
from drf_spectacular.openapi import AutoSchema as BaseAutoSchema
8-
from drf_spectacular.utils import PolymorphicProxySerializer
8+
from drf_spectacular.utils import OpenApiExample, PolymorphicProxySerializer
99
from inflection import camelize
1010
from rest_framework import serializers
1111
from rest_framework.negotiation import DefaultContentNegotiation
@@ -338,11 +338,23 @@ def _get_extra_validation_errors(self) -> Dict[str, Set[str]]:
338338
def _get_examples(
339339
self, serializer, direction, media_type, status_code=None, extras=None
340340
):
341-
all_examples = (extras or []) + get_error_examples()
341+
if direction == "response":
342+
all_examples = (extras or []) + self._get_error_response_examples()
343+
else:
344+
all_examples = extras
342345
return super()._get_examples(
343346
serializer,
344347
direction,
345348
media_type,
346349
status_code=status_code,
347350
extras=all_examples,
348351
)
352+
353+
def _get_error_response_examples(self) -> List[OpenApiExample]:
354+
status_codes = set(self._get_allowed_error_status_codes())
355+
examples = get_error_examples()
356+
return [
357+
example
358+
for example in examples
359+
if status_codes.intersection(example.status_codes)
360+
]

tests/test_openapi.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,3 +656,77 @@ def test_examples_from_extend_schema_serializer_are_showing_up(api_client):
656656
assert (
657657
examples["ExtendSchemaSerializerExample"]["value"]["field"] == "specific_value"
658658
)
659+
660+
661+
class CustomError403Serializer(serializers.Serializer):
662+
code = serializers.ChoiceField(choices=[("perm_denied", "perm_denied")])
663+
detail = serializers.CharField()
664+
attr = serializers.CharField(allow_null=True)
665+
666+
667+
class CustomErrorResponse403Serializer(serializers.Serializer):
668+
type = serializers.ChoiceField(choices=ClientErrorEnum.choices)
669+
errors = CustomError403Serializer(many=True)
670+
671+
672+
class ExpSerializer(serializers.Serializer):
673+
field = serializers.CharField()
674+
675+
676+
class ExamplesView(GenericAPIView):
677+
authentication_classes = [BasicAuthentication]
678+
permission_classes = [IsAuthenticated, IsAdminUser]
679+
serializer_class = ExpSerializer
680+
681+
@extend_schema(
682+
responses={
683+
403: OpenApiResponse(
684+
response=CustomErrorResponse403Serializer,
685+
description="Registration is disabled",
686+
)
687+
},
688+
examples=[
689+
OpenApiExample(
690+
"Example",
691+
summary="short summary",
692+
description="longer description",
693+
value={
694+
"type": "client_error",
695+
"errors": [
696+
{
697+
"code": "perm_denied",
698+
"detail": "Registration is disabled.",
699+
"attr": None,
700+
}
701+
],
702+
},
703+
status_codes=[403],
704+
),
705+
],
706+
)
707+
def get(self, request, *args, **kwargs):
708+
serializer = self.get_serializer(instance={"field": "value1"})
709+
return Response(serializer.data)
710+
711+
712+
def test_default_examples_are_showing_up_only_when_status_code_is_allowed(
713+
api_client, settings
714+
):
715+
settings.DRF_STANDARDIZED_ERRORS = {"ALLOWED_ERROR_STATUS_CODES": ["403"]}
716+
717+
route = "perm-denied/"
718+
view = ExamplesView.as_view()
719+
schema = generate_view_schema(route, view)
720+
responses = get_responses(schema, route)
721+
examples = responses["403"]["content"]["application/json"]["examples"]
722+
assert "Example" in examples
723+
assert "PermissionDenied" in examples
724+
725+
settings.DRF_STANDARDIZED_ERRORS = {"ALLOWED_ERROR_STATUS_CODES": []}
726+
route = "perm-denied/"
727+
view = ExamplesView.as_view()
728+
schema = generate_view_schema(route, view)
729+
responses = get_responses(schema, route)
730+
examples = responses["403"]["content"]["application/json"]["examples"]
731+
assert "Example" in examples
732+
assert "PermissionDenied" not in examples

0 commit comments

Comments
 (0)