Skip to content

A router for ViewSets and View ! And with better browsable API !

License

Notifications You must be signed in to change notification settings

enzofrnt/djangorestframework-hybridrouter

Repository files navigation

djangorestframework-hybridrouter

A router for ViewSets and APIViews, with a better browsable API and support for nested routers!

Inspired by this topic.

Overview

The HybridRouter class is an extension of Django REST Framework's DefaultRouter that allows you to register both ViewSets and APIViews. It provides more flexibility in managing your URL routes, offers a better browsable API experience, and supports nested routers.

Features

  • Register both ViewSets and APIViews using a unified interface.
  • Simplified URL patterns for better readability.
  • Automatic creation of intermediate API views for grouped endpoints (configurable).
  • Support for nested routers.
  • Automatic conflict resolution for basenames.

Installation

pip install djangorestframework-hybridrouter

Usage

Here’s an example of how to use the HybridRouter:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from django.urls import path, include
from hybrid_router import HybridRouter


class ServerConfigViewSet(ViewSet):
    def list(self, request):
        return Response({'a': 'b'})

class ServerConfigView(APIView):
    def get(self, request):
        return Response({'config': 'server'})

class ClientModsView(APIView):
    def get(self, request):
        return Response({'mods': 'client'})

class ServerModsView(APIView):
    def get(self, request):
        return Response({'mods': 'server'})

router = HybridRouter()
router.include_intermediate_views = True  # Enable intermediate API views

# Register APIViews
router.register('server-config', ServerConfigView, basename='server-config')
router.register('mods/client', ClientModsView, basename='mods-client')
router.register('mods/server', ServerModsView, basename='mods-server')

# Register a ViewSet
router.register('coucou', ServerConfigViewSet, basename='coucou')

# Register more APIViews under 'coucou' prefix
router.register('coucou/client', ClientModsView, basename='coucou-client')
router.register('coucou/server', ServerModsView, basename='coucou-server')

urlpatterns = [
    path('', include(router.urls)),
]

This configuration will generate URLs for both APIViews and ViewSets, and include intermediate API views for grouped endpoints.

Documentation

HybridRouter

  • register(prefix, view, basename=None)

    Registers an APIView or ViewSet with the specified prefix.

    • prefix: URL prefix for the view or viewset.
    • view: The APIView or ViewSet class.
    • basename: The base name for the view or viewset (optional). If not provided, it will be automatically generated.
  • register_nested_router(prefix, router)

    Registers a nested router under a specific prefix.

    • prefix: URL prefix under which the nested router will be registered.
    • router: The DRF router instance to be nested.

Attributes

  • include_intermediate_views (default True)

    Controls whether intermediate API views are automatically created for grouped endpoints. When set to True, the router will generate intermediate views that provide a browsable API listing of all endpoints under a common prefix.

Notes

  • Automatic Basename Conflict Resolution

    The HybridRouter automatically handles conflict resolution for basenames. If you register multiple views or viewsets with the same basename, it will assign unique basenames and log a warning.

  • Trailing Slash

    The HybridRouter uses a configurable trailing_slash attribute, defaulting to "/?" to match DRF’s SimpleRouter behavior.

Advanced Features

Custom Intermediary API Views

The HybridRouter can automatically create custom intermediary API views for grouped endpoints. This feature improves the organization of your API and provides a cleaner browsable interface.

Example:

router = HybridRouter()
router.include_intermediate_views = True  # Enable intermediate API views

router.register('server-config', ServerConfigView, basename='server-config')
router.register('server-config/map', ServerConfigView, basename='server-config')
router.register('server-config/health', ServerConfigView, basename='server-config')
router.register('mods/client', ClientModsView, basename='mods-client')
router.register('mods/server', ServerModsView, basename='mods-server')

With include_intermediate_views set to True, the router will create intermediate views at the mods/ prefix, providing a browsable API that lists both client and server endpoints under mods/. Also note that here for server-config/ endpoints an intermediate view will not be created because it's already registered.

Nested Routers

You can register nested routers under a specific prefix using register_nested_router. This allows you to include routers from other apps or create a complex URL structure.

Example:

from rest_framework.routers import DefaultRouter

nested_router = DefaultRouter()
nested_router.register('items', ItemViewSet, basename='item')

router = HybridRouter()
router.register_nested_router('nested/', nested_router)

urlpatterns = [
    path('', include(router.urls)),
]

In this example, all routes from nested_router will be available under the nested/ prefix.

Experimental Features

The automatic creation of intermediary API views is a feature that improves the browsable API experience. This feature is still in development and may not work as expected in all cases. Please report any issues or suggestions.

router = HybridRouter(enable_intermediate_apiviews=False)

router.register('server-config', ServerConfigView, name='server-config')
router.register('mods/client', ClientModsView, name='mods-client')
router.register('mods/server', ServerModsView, name='mods-server')
router.register('coucou/client', ClientModsView, name='coucou-client')
router.register('coucou/server', ServerModsView, name='coucou-server')
router.register('coucou', ServerConfigViewSet, basename='coucou')

With this configuration of the router with enable_intermediate_apiviewsset to False, the intermediary API views will not be created. So the browsable API will look like on a DefaultRouter :

image

But if you set enable_intermediate_apiviews to True, the intermediary API views will be created and the browsable API will look like this:

router = HybridRouter(enable_intermediate_apiviews=True)

image image

This improves the readability and the logic of the browsable API and provides a better user experience.

And as you can see that will not interfere with other already existing views. Here, the ServerConfigViewSet is still accessible through the coucou endpoint and as not been overridden by an intermediary API view.

Testing

The package includes comprehensive tests to ensure reliability. Here are some highlights:

  • Registering Views and ViewSets Tests registering both APIViews and ViewSets, ensuring that URLs are correctly generated and accessible.

  • Intermediate Views Tests the creation of intermediate views when include_intermediate_views is enabled or disabled.

  • Nested Routers Tests registering nested routers and ensuring that their routes are correctly included under the specified prefix.

  • Basename Conflict Resolution Tests automatic conflict resolution when multiple views or viewsets are registered with the same basename.

Notes

  • Compatibility

    The HybridRouter is designed to work seamlessly with Django REST Framework and is compatible with existing DRF features like schema generation.

  • Spectacular Support

    Will be added in the future. After some manual test, it seems that the spectacular package is compatible with the HybridRouter. But that may need some more testing.

About

A router for ViewSets and View ! And with better browsable API !

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages