Basic Example ============= This example demonstrates a simple WebSocket application using Chanx. It includes an echo service with authentication and structured messages, showing the fundamental features of the framework. Project Setup ------------- First, let's create a basic Django project structure: .. code-block:: bash myproject/ ├── manage.py ├── myproject/ │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── echo/ ├── __init__.py ├── consumers.py ├── messages.py ├── routing.py └── templates/ └── echo/ └── index.html Message Types ------------- Define message types in `echo/messages.py`: .. code-block:: python from typing import Any, Literal, Optional from chanx.messages.base import BaseMessage from chanx.messages.incoming import PingMessage class EchoMessage(BaseMessage): """Message for echoing text back to the client.""" action: Literal["echo"] = "echo" payload: str class StatusMessage(BaseMessage): """Message for sending status updates.""" action: Literal["status"] = "status" payload: str # Define incoming message union EchoIncomingMessage = PingMessage | EchoMessage WebSocket Consumer ------------------ Create a consumer in `echo/consumers.py`: .. code-block:: python from typing import Any from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from chanx.generic.websocket import AsyncJsonWebsocketConsumer from chanx.messages.incoming import PingMessage from chanx.messages.outgoing import PongMessage from echo.messages import EchoIncomingMessage, EchoMessage, StatusMessage class EchoConsumer(AsyncJsonWebsocketConsumer[EchoIncomingMessage]): """ Simple echo consumer that responds to messages. Demonstrates basic authentication and message handling with Chanx. """ # Authentication setup authentication_classes = [SessionAuthentication] permission_classes = [IsAuthenticated] # Enable completion messages send_completion = True async def post_authentication(self) -> None: """Actions after successful authentication.""" # Send a welcome message after connection authentication user = self.user await self.send_message( StatusMessage(payload=f"Welcome, {user.username}!") ) async def receive_message(self, message: EchoIncomingMessage, **kwargs: Any) -> None: """Handle incoming messages.""" # Handle different message types using pattern matching match message: case PingMessage(): # Respond to ping with pong await self.send_message(PongMessage()) case EchoMessage(payload=payload): # Echo the message back with the user's name user = self.user echo_text = f"{user.username}: {payload}" await self.send_message(EchoMessage(payload=echo_text)) case _: # Handle any other messages pass WebSocket Routing ----------------- Set up routing in `echo/routing.py`: .. code-block:: python from channels.routing import URLRouter from chanx.routing import path from echo.consumers import EchoConsumer # Important: name this variable 'router' for string-based includes router = URLRouter([ path('echo/', EchoConsumer.as_asgi()), ]) ASGI Configuration ------------------ Configure the ASGI application in `myproject/asgi.py`: .. code-block:: python import os from channels.routing import ProtocolTypeRouter from channels.security.websocket import OriginValidator from channels.sessions import CookieMiddleware from django.core.asgi import get_asgi_application from django.conf import settings from chanx.routing import include os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings") django_asgi_app = get_asgi_application() routing = { "http": django_asgi_app, "websocket": OriginValidator( CookieMiddleware(include("echo.routing")), settings.CORS_ALLOWED_ORIGINS + settings.CSRF_TRUSTED_ORIGINS, ), } application = ProtocolTypeRouter(routing) Settings Configuration ---------------------- Update `myproject/settings.py` with Channels and Chanx settings: .. code-block:: python INSTALLED_APPS = [ # Django apps "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", # Third-party apps "daphne", "channels", "rest_framework", "chanx.playground", # Enable the WebSocket playground # Local apps "echo", ] # Channels configuration ASGI_APPLICATION = "myproject.asgi.application" CHANNEL_LAYERS = { "default": { "BACKEND": "channels.layers.InMemoryChannelLayer" # For production, use Redis: # "BACKEND": "channels_redis.core.RedisChannelLayer", # "CONFIG": { # "hosts": [("127.0.0.1", 6379)], # }, } } # Chanx settings CHANX = { "SEND_COMPLETION": True, "SEND_AUTHENTICATION_MESSAGE": True, "LOG_RECEIVED_MESSAGE": True, "LOG_SENT_MESSAGE": True, } # CORS/CSRF settings for WebSocket CORS_ALLOWED_ORIGINS = ["http://localhost:8000"] CSRF_TRUSTED_ORIGINS = ["http://localhost:8000"] HTML Template ------------- Create a simple frontend in `echo/templates/echo/index.html`: .. code-block:: html Chanx Echo Example

Chanx Echo Example

Django View ----------- Create a view to render the template in `echo/views.py`: .. code-block:: python from django.contrib.auth.decorators import login_required from django.shortcuts import render @login_required def echo_view(request): """Render the echo application page.""" return render(request, "echo/index.html") URL Configuration ----------------- Add the view to your URL configuration in `myproject/urls.py`: .. code-block:: python from django.contrib import admin from django.urls import path, include from echo import views urlpatterns = [ path("admin/", admin.site.urls), # Echo application view path("echo/", views.echo_view, name="echo"), # Add the playground for development path("playground/", include("chanx.playground.urls")), ] Testing the Consumer -------------------- For proper testing, make sure to configure completion messages in your test settings: .. code-block:: python # settings/test.py CHANX = { "SEND_COMPLETION": True, # Essential for receive_all_json() to work properly } Let's write a test for our consumer in `echo/tests.py`: .. code-block:: python from django.contrib.auth.models import User from chanx.testing import WebsocketTestCase from echo.messages import EchoMessage class EchoConsumerTests(WebsocketTestCase): """Tests for the EchoConsumer.""" ws_path = "/ws/echo/" def setUp(self): super().setUp() # Create test user self.user = User.objects.create_user( username="testuser", password="testpassword" ) # Log in with the test client self.client.login(username="testuser", password="testpassword") def get_ws_headers(self): """Provide session cookie for WebSocket authentication.""" cookies = self.client.cookies return [ (b"cookie", f"sessionid={cookies['sessionid'].value}".encode()), ] async def test_echo_message(self): """Test sending and receiving echo messages.""" # Connect using the default communicator await self.auth_communicator.connect() # Verify authentication succeeded await self.auth_communicator.assert_authenticated_status_ok() # Should receive welcome message welcome = await self.auth_communicator.receive_json_from() assert welcome["action"] == "status" assert "Welcome" in welcome["payload"] # Skip completion message await self.auth_communicator.receive_json_from() # Send an echo message test_message = "Hello, world!" await self.auth_communicator.send_message(EchoMessage(payload=test_message)) # Receive the echo response response = await self.auth_communicator.receive_json_from() # Verify the response assert response["action"] == "echo" assert response["payload"] == f"testuser: {test_message}" # Disconnect await self.auth_communicator.disconnect() Running the Example ------------------- 1. Install the dependencies: .. code-block:: bash pip install django djangorestframework channels chanx 2. Run migrations: .. code-block:: bash python manage.py migrate 3. Create a superuser: .. code-block:: bash python manage.py createsuperuser 4. Start the development server: .. code-block:: bash python manage.py runserver 5. Access the application: - Login page: http://localhost:8000/admin/login/ - Echo application: http://localhost:8000/echo/ - WebSocket playground: http://localhost:8000/playground/websocket/ Key Concepts Demonstrated ------------------------- This example demonstrates several key Chanx features: 1. **Authentication**: Using SessionAuthentication to secure WebSocket connections 2. **Message Schemas**: Defining structured message types with Pydantic validation 3. **Consumer Lifecycle**: Handling connection, authentication, and messages 4. **Message Handling**: Processing different message types using pattern matching 5. **Testing**: Using WebsocketTestCase to test WebSocket consumers 6. **Frontend Integration**: Building a simple JavaScript client Extensions and Next Steps ------------------------- To build on this example, you could: 1. **Add Group Messaging**: Implement broadcast functionality to all connected clients 2. **Implement User Status**: Track and display online/offline status of users 3. **Add Message History**: Store messages in a database and provide history on connection 4. **Create Multiple Rooms**: Support multiple chat rooms with separate channels 5. **Add Message Validation**: Implement more complex message validation with Pydantic For a more complex example, see the :doc:`chat` application that builds on these concepts.