Drf-yasg: Adding an endpoint breaks grouping

Created on 8 Nov 2019  路  3Comments  路  Source: axnsan12/drf-yasg

Hi.
We have the following documentation:
image
as you can see, endpoints are grouped based on "viewsets" (tags named after its url/viewset name).

If we add a very simple endpoint:

# views.py
class StatusView(APIView):
    permission_classes = [AllowAny]

    # pylint: disable=redefined-builtin
    def get(self, request, *args, **kwargs):
        return Response({"status": "ok"})

# urls.py
urlpatterns = [
    re_path(r"^status/", StatusView.as_view()),
    re_path(
        r"^docs/$", SchemaView.with_ui("redoc", cache_timeout=0), name="schema-redoc"
    ),
    re_path(
        r"^docs/swagger(?P<format>\.json|\.yaml)/$",
        SchemaView.without_ui(cache_timeout=0),
        name="schema",
    ),
    re_path(
        r"^api/v1/",
        include(([*quotas_patterns, *users_patterns], "api"), namespace="v1"),
    )
]

the grouping gets broken:
image

image

It's because after adding this endpoint, the generated OpenAPI spec tags are simply having api and not the previous names.

Even after trying to tweak it by adding swagger_auto_schema with explicit tags:

class StatusView(APIView):
    permission_classes = [AllowAny]

    @never_cache
    @swagger_auto_schema(
        operation_id="status",
        tags=["api"],
        responses={200: StatusSerializer},
    )
    # pylint: disable=redefined-builtin
    def get(self, request, *args, **kwargs):
        return Response({"status": "ok"})

the grouping is broken - the status is under api group but that's the same as for any other endpoint. In the swagger.yaml schema, I can see that all of endpoints have simply tags: api instead of e.g. tags: quota as it has before.

Is there a way how to fix this?

Most helpful comment

Yeah, thanks, this did the trick:

from drf_yasg.inspectors import SwaggerAutoSchema


class SquadSwaggerAutoSchema(SwaggerAutoSchema):
    def get_tags(self, operation_keys=None):
        tags = super().get_tags(operation_keys)

        if "api" in tags and operation_keys:
            # NOTE: `operation_keys` is a list like ["api", "v1", "token", "read"].
            tags[0] = operation_keys[2]

        return tags

cc who came up with it @DusanMadar

All 3 comments

I think the way to go would be to subclass SwaggerAutoSchema and to override the get_tags() method to return the tags you want. Note that you don't only have to work with the provided operation_keys, you can also access the currently inspected view as self.view if needed.

Yeah, thanks, this did the trick:

from drf_yasg.inspectors import SwaggerAutoSchema


class SquadSwaggerAutoSchema(SwaggerAutoSchema):
    def get_tags(self, operation_keys=None):
        tags = super().get_tags(operation_keys)

        if "api" in tags and operation_keys:
            # NOTE: `operation_keys` is a list like ["api", "v1", "token", "read"].
            tags[0] = operation_keys[2]

        return tags

cc who came up with it @DusanMadar

In my case I've implemented following solution, in you settings define default schema class:

SWAGGER_SETTINGS = {
   'DEFAULT_AUTO_SCHEMA_CLASS': 'app.models.CustomSwaggerAutoSchema',
}

and based on the comments of @hnykda and @etene:

from drf_yasg.inspectors import SwaggerAutoSchema


class CustomSwaggerAutoSchema(SwaggerAutoSchema):
    def get_tags(self, operation_keys=None):
        operation_keys = operation_keys or self.operation_keys

        tags = self.overrides.get('tags')
        if not tags:
            tags = [operation_keys[0]]
        if hasattr(self.view, "swagger_tags"):
            tags = self.view.swagger_tags

        return tags

Then you can define the tags on view:

class PageView(ApiView):
    ...
    swagger_tags = ["tag1"]
    ...

class PageView2(ApiView):
    ...
    swagger_tags = ["tag1", "tag2"]
    ...

class PageView3(ApiView):
    ...
    swagger_tags = ["tag3"]
    ...
Was this page helpful?
0 / 5 - 0 ratings

Related issues

gertjanol picture gertjanol  路  5Comments

mkurnikov picture mkurnikov  路  3Comments

marcosgeorgopoulos picture marcosgeorgopoulos  路  4Comments

vinayan3 picture vinayan3  路  5Comments

Amoki picture Amoki  路  4Comments