Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Grouping on OpenAPI endpoints with Django Rest Framework

I have a Django project and I am using Django REST framework. I am using drf-spectacular for OpenAPI representation, but I think my problem is not tied to this package, it's seems a more generic OpenAPI thing to me (but not 100% sure if I am right to this).

Assume that I have a URL structure like this:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include([
        path('v1/', include([
            path('auth/', include('rest_framework.urls', namespace='rest_framework')),
            path('jwt-auth/token/obtain', CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
            path('jwt-auth/token/refresh', CustomTokenRefreshView.as_view(), name='token_refresh'),
            path('home/', include("home.urls"))
        ]))
    ])),

    # OpenAPI endpoints
    path('swagger/', SpectacularSwaggerView.as_view(url_name='schema-swagger-json'), name='schema-swagger-ui'),
    path('swagger.yaml/', SpectacularAPIView.as_view(), name='schema-swagger-yaml'),
    path('swagger.json/', SpectacularJSONAPIView.as_view(), name='schema-swagger-json'),
    path('redoc/', SpectacularRedocView.as_view(url_name='schema-swagger-yaml'), name='schema-redoc'),
]

In the corresponding swagger UI view, I get all endpoints grouped under api endpoint, e.g.: enter image description here

If add more endpoints under v1, all go under the api endpoint.

What I want to achieve is, to have the endpoints in Swagger grouped differently, e.g. by app. So I'd have home, jwt, another_endpoint, instead of just api, so it will be easier to navigate in Swagger (when I add more endpoints, with the current method it's just showing a massive list of URLs, not very user friendly).

I've read that those groups are being extracted from the first path of a URL, in my case this is api, so if I change the URL structure, I could achieve what I need.

But isn't there another way of doing this? I want to keep my URL structure, and customize how I display this with OpenAPI, so in the end I have a swagger that groups the endpoints by app, so it's easier to navigate and find what you are looking for.

like image 210
babis21 Avatar asked Jul 10 '20 08:07

babis21


2 Answers

you are making it harder than it needs to be. In the global settings you can specify a common prefix regex that strips the unwanted parts. that would clean up both operation_id and tags for you. In your case that would probably be:

SPECTACULAR_SETTINGS = {
    'SCHEMA_PATH_PREFIX': r'/api/v[0-9]',
}

that should result in tags: home, jwt-auth, swagger.json, swagger.yaml

the tags on @extend_schema is merely a convenience to deviate from the default where needed. it would be cumbersome to do this for every operation. see the settings for more details:

https://drf-spectacular.readthedocs.io/en/latest/settings.html

for even more elaborate tagging you can always subclass AutoSchema and override get_tags(self) to your liking. cheers!

like image 153
Insa Avatar answered Oct 19 '22 16:10

Insa


Turns out that you can control this by changing the tags in a view, as per OpenAPI specification: https://swagger.io/docs/specification/grouping-operations-with-tags/

So, with drf-spectacular, you can use the extend_schema decorator to achieve this, e.g.:

from drf_spectacular.utils import extend_schema

class CustomTokenObtainPairView(TokenObtainPairView):
    """
    Takes a set of user credentials and returns an access and refresh JSON web
    token pair to prove the authentication of those credentials.
    """
    @extend_schema(
        operation_id="jwt_obtain",
        ....
        tags=["aTestTag"]
    )
    def post(self, request, *args, **kwargs):
        # whatever

So you have to use this decorator to extend the schema in each view that you want to put into a custom group.

like image 20
babis21 Avatar answered Oct 19 '22 17:10

babis21