Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

extend_schema_serializer(examples=[...]) causes list endpoint examples to be singular items #595

Closed
eviltwin opened this issue Nov 4, 2021 · 7 comments
Labels
bug Something isn't working fix confirmation pending issue has been fixed and confirmation from issue reporter is pending

Comments

@eviltwin
Copy link

eviltwin commented Nov 4, 2021

Describe the bug
When providing example responses on schemas with extend_schema_serializer, the documentation in redoc starts showing a single item response for the list endpoints instead of the correct list format with (potentially) information about next/previous cursor pagination etc.

To Reproduce

@extend_schema_serializer(
    exclude_fields=('single',), # schema ignore these fields
    examples = [
         OpenApiExample(
            'Valid example 1',
            summary='short summary',
            description='longer description',
            value={
                'songs': {'top10': True},
                'single': {'top10': True}
            },
        ),
    ]
)
class AlbumSerializer(serializers.ModelSerializer):
    songs = SongSerializer(many=True)
    single = SongSerializer(read_only=True)

    class Meta:
        fields = '__all__'
        model = Album
        
class AlbumViewSet(viewsets.ReadOnlyModelViewSet):
    serializer_class = AlbumSerializer
    queryset = Album.objects.all()
    pagination_class = CursorPagination

Expected behavior
Correct list-based example responses should be generated, where the items in the list are composed of the example values provided to extend_schema_serializer.

tfranzel added a commit that referenced this issue Mar 16, 2022
@tfranzel tfranzel added bug Something isn't working fix confirmation pending issue has been fixed and confirmation from issue reporter is pending labels Mar 17, 2022
@tfranzel
Copy link
Owner

This got finally fixed in 0.22.0. Let me know if that works for you.

@XF-FW
Copy link

XF-FW commented Mar 24, 2022

For those who find the opposite problem after upgrading: You provided an example, that's not a list, but it got converted to a list anyway.

You might be missing the parameter many=False to the extend_schema_serializer decorator.

@tfranzel
Copy link
Owner

Yeah sry about that. That is partly why the release was a y-stream release instead of a z-stream. However, I hope the new fixed behavior is what most users would expect, principle of least surprise and such.

You might be missing the parameter many=False to the extend_schema_serializer decorator.

That is the way. What I find odd is the logic behind this is almost identical to the wrapping of the response (serializers) into lists. I would assume that the response must have been wrongly wrapped for you too then.

@XF-FW
Copy link

XF-FW commented Mar 24, 2022

Yeah sry about that. That is partly why the release was a y-stream release instead of a z-stream. However, I hope the new fixed behavior is what most users would expect, principle of least surprise and such.

Completely fine. Spend some time searching until I found this thread, downgraded and it worked, then I recalled there was a many parameter, so I upgraded it again after adding it and it was all working again. I just left the message to spare a few minutes for whomever finds this as I did.

That is the way. What I find odd is the logic behind this is almost identical to the wrapping of the response (serializers) into lists. I would assume that the response must have been wrongly wrapped for you too then.

That makes sense. Tbf, what I'm building is still in development and my case might have been more peculiar than I thought. It's a list endpoint, so there's no request body. I'm also using response_only=True, although I admit, I'm not completely sure it's necessary. The docs don't say anything about it other than # signal that example only applies to responses and I haven't found the time to dig on the code to figure it out.

@tfranzel
Copy link
Owner

It's a list endpoint

If its a list endpoint and you attach an example to the serializer via @extend_schema_serializer, the example should now be a plain example (not a list) and the list detection should then take care of the rest. If you have a list endpoint that explicitly does not return a "simple" list, then your solution is one possible way. This pattern usually comes up with envelopes. Have a look at this FAQ entry

I'm also using response_only=True

this just makes the example not show up for the request, but since its a get/list endpoint, it wouldn't have shown up anyway. should make no difference. It should only make a difference if there is in fact a request body, otherwise it would likely be a bug.

@XF-FW
Copy link

XF-FW commented Mar 24, 2022

This pattern usually comes up with envelopes.

Yeah, that's was my use case. I needed to add some metadata to the endpoint. The FAQ entry was helpful indeed and my solution doesn't stray too much from it. The main difference is that I create a serializer with enveloper(XSerializer) and set it on get_serializer_class, so I don't need to add the list method to the ViewSet.

it wouldn't have shown up anyway.

Thank you for clarifying this and for your suggestions! Appreciate it.

@AlexChalk
Copy link

Hey folks, this solution will break on nested pagination schemas, e.g.

    def get_paginated_response_schema(self, schema):
        return {
            "type": "object",
            "properties": {
                "pagination": {
                    "type": "object",
                    "properties": {
                        "count": {"type": "integer", "example": 10},
                        "next": {
                            "type": "string",
                            "nullable": True,
                            "format": "uri",
                            "example": None,
                        },
                        "previous": {
                            "type": "string",
                            "nullable": True,
                            "format": "uri",
                            "example": None,
                        },
                        "page_size": {"type": "integer", "example": 10},
                        "num_pages": {"type": "integer", "example": 1},
                        "current_page": {"type": "integer", "example": 1},
                    },
                },
                "data": schema,
            },
        }

I don't have time to submit a fix right away, but I think the gist is you just need to recursively loop on openapi types with "properties".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fix confirmation pending issue has been fixed and confirmation from issue reporter is pending
Projects
None yet
Development

No branches or pull requests

4 participants