Exposing a Django REST-like API over a WebSocket Connection


Django Channels REST Framework is a selection of useful tools for building WebSocket API consumers with Django Channels v2. It focuses on enabling you to re-use your existing Django REST framework code.


One of the key features that DCRF provides is the ability to easily create JSON WebSocket consumers that can expose REST-like actions in the same way as the GenericApiView in DRF.


from django.contrib.auth import get_user_model

from djangochannelsrestframework import permissions
from djangochannelsrestframework.generics import GenericAsyncAPIConsumer
from djangochannelsrestframework.mixins import ListModelMixin

from . import serializers

class UserConsumer(ListModelMixin, GenericAsyncAPIConsumer):
    queryset = get_user_modle().objects.all()
    serializer_class = serializers.UserSerializer
    permission_classes = (permissions.IsAuthenticated,)


This consumer will expose a list action that you can call over the WebSocket connection by sending a ws message.


{
  "action": "list",
  "request_id": 42 // this value is included in your response message, to help you track multiple pending actions
}


The consumer will use your queryset to retrieve a list of items and encode a JSON response using the DRF serializer_class provided. Like GeneicApiViews in DRF you can override get_queryset and filter_queryset methods.


DCRF includes a collection of other usefull ModelMixins:

  • CreateModelMixin
  • ListModelMixin
  • RetrieveModelMixin
  • UpdateModelMixin
  • PatchModelMixin
  • DeleteModelMixin


These can be added to the GenericAsyncAPIConsumer as mixins.


To use them over the WebSocket you will need to include the action value: action: "update". For actions that operate on a model instance (retrieve, update, patch and delete) you also need pk: 42. Then include the data for your action: data: {"username": "bob"}.



Adding Custom Actions


In a normal REST API sometimes we need to add custom action endpoints that are outside of the regular CRUD operations we all know and love. With DCRF there is a convenient @action() method decorator that you can add to a method to expose it to your WebSocket clients.


from djangochannelsrestframework.decorators import action
from djangochannelsrestframework.consumers import AsyncAPIConsumer

class MyConsumer(AsyncAPIConsumer):

    @action()
    async def an_async_action(self, some=None, **kwargs):
        # do something async
        return {'response_with': 'some message'}, 200


In your client you would send a message like this.


{
    "action": "an_async_action",
    "request_id": 42,
    "some": "value passed as keyword argument to action"
}


You can also add actions to your GenericAsyncAPIConsumer, so that you can have multiple methods on the same consumer (this is how the mixins add their actions).



Calling your Django Views over WebSocket


It is also possible to use view_as_consumer method to automatically wrap an existing Django view to be accessible over a WebSocket connection.


from djangochannelsrestframework.consumers import view_as_consumer

application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter([
            url(r"^front(end)/$", view_as_consumer(YourDjangoView)),
        ])
    ),
 })


It is also possible to subscribe to changes of models using DjangoChannelsRestFramework see our recent post.


When using DCRF it is very helpful to set up multiple consumers behind a Multiplexing layer, so that you can have a single WebSocket connection call multiple consumers concurrently.