Helps build a RESTful API on top of WebSockets using channels.
Project description
Channels API
Channels API exposes a RESTful Streaming API over WebSockets using channels. It provides a ResourceBinding which is comparable to Django Rest Framework’s ModelViewSet. It is based on DRF serializer classes.
It requires Python 3, Channels >0.17.3, Django >1.8, and Django Rest Framework 3.0
Table of Contents
How does it work?
The API builds on top of channels’ WebsocketBinding class. It works by having the client send a stream and payload parameters. This allows us to route messages to different streams (or resources) for a particular action. So POST /user would have a message that looks like the following
var msg = {
stream: "users",
payload: {
action: "create",
data: {
email: "test@example.com",
password: "password",
}
}
}
ws.send(JSON.stringify(msg))
Why?
You’re already using Django Rest Framework and want to expose similar logic over WebSockets.
WebSockets can publish updates to clients without a request. This is helpful when a resource can be edited by multiple users across many platforms.
Getting Started
This tutorial assumes you’re familiar with channels and have completed the Getting Started
Add channels_api to requirements.txt
pip install channels_api
Add channels_api to INSTALLED_APPS
INSTALLED_APPS = (
'rest_framework',
'channels',
'channels_api'
)
Add your first resource binding
# polls/bindings.py
from channels_api.bindings import ResourceBinding
from .models import Question
from .serializers import QuestionSerializer
class QuestionBinding(ResourceBinding):
model = Question
stream = "questions"
serializer_class = QuestionSerializer
queryset = Question.objects.all()
Add a WebsocketDemultiplexer to your channel_routing
# proj/routing.py
from channels.generic.websockets import WebsocketDemultiplexer
from channels.routing import route_class
from polls.bindings import QuestionBinding
class APIDemultiplexer(WebsocketDemultiplexer):
consumers = {
'questions': QuestionBinding.consumer
}
channel_routing = [
route_class(APIDemultiplexer)
]
That’s it. You can now make REST WebSocket requests to the server.
var ws = new WebSocket("ws://" + window.location.host + "/")
ws.onmessage = function(e){
console.log(e.data)
}
var msg = {
stream: "questions",
payload: {
action: "create",
data: {
question_text: "What is your favorite python package?"
},
request_id: "some-guid"
}
}
ws.send(JSON.stringify(msg))
// response
{
stream: "questions",
payload: {
action: "create",
data: {
id: "1",
question_text: "What is your favorite python package"
}
errors: [],
response_status: 200
request_id: "some-guid"
}
}
Add the channels debugger page (Optional)
This page is helpful to debug API requests from the browser and see the response. It is only designed to be used when DEBUG=TRUE.
# proj/urls.py
from django.conf.urls import include
urlpatterns = [
url(r'^channels-api/', include('channels_api.urls'))
]
ResourceBinding
By default the ResourceBinding implements the following REST methods:
create
retrieve
update
list
delete
subscribe
See the test suite for usage examples for each method.
List Pagination
Pagination is handled by django.core.paginator.Paginator
You can configure the DEFAULT_PAGE_SIZE by overriding the settings.
# settings.py
CHANNELS_API = {
'DEFAULT_PAGE_SIZE': 25
}
Subscriptions
Subscriptions are a way to programmatically receive updates from the server whenever a resource is created, updated, or deleted
By default channels-api has implemented the following subscriptions
create a Resource
update any Resource
update this Resource
delete any Resource
delete this Resource
To subscribe to a particular event just use the subscribe action with the parameters to filter
// get an event when any question is updated
var msg = {
stream: "questions",
payload: {
action: "subscribe",
data: {
action: "update"
}
}
}
// get an event when question(1) is updated
var msg = {
stream: "questions",
payload: {
action: "subscribe"
data: {
action: "update",
pk: "1"
}
}
}
Custom Actions
To add your own custom actions, use the detail_action or list_action decorators.
from channels_api.bindings import ResourceBinding
from channels_api.decorators import detail_action, list_action
from .models import Question
from .serializers import QuestionSerializer
class QuestionBinding(ResourceBinding):
model = Question
stream = "questions"
serializer_class = QuestionSerializer
queryset = Question.objects.all()
@detail_action()
def publish(self, pk, data=None, **kwargs):
instance = self.get_object(pk)
result = instance.publish()
return result, 200
@list_action()
def report(self, data=None, **kwargs):
report = self.get_queryset().build_report()
return report, 200
Then pass the method name as “action” in your message
// run the publish() custom action on Question 1
var msg = {
stream: "questions",
payload: {
action: "publish",
data: {
pk: "1"
}
}
}
// run the report() custom action on all Questions
var msg = {
stream: "questions",
payload: {
action: "report"
}
}
Permissions
Channels API offers a simple permission class system inspired by rest_framework. There are two provided permission classes: AllowAny and IsAuthenticated.
To configure permissions globally use the setting DEFAULT_PERMISSION_CLASSES like so
# settings.py
CHANNELS_API = {
'DEFAULT_PERMISSION_CLASSES': ('channels_api.permissions.AllowAny',)
}
You can also configure the permission classes on a ResourceBinding itself like so
from channels_api.permissions import IsAuthenticated
class MyBinding(ResourceBinding):
permission_classes = (IsAuthenticated,)
Lastly, to implement your own permission class, override the has_permission of BasePermission.
from channels_api.permissions import BasePermission
class MyPermission(BasePermission):
def has_permission(self, user, action, pk):
if action == "CREATE":
return True
return False
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for channels_api-0.4.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 74724c921ccfc168c4cc18287b557b7fcb0d034562bd9071abe5e6b95ad75059 |
|
MD5 | a6c95182063bb5b185cce3e9f977c42b |
|
BLAKE2b-256 | d7e53d64acfa2996a87f01adafce03e1d1212e6c789c717b33fc4a666e28de79 |