Tutorial Part 3: Routing and browser client

The Socket.IO endpoint receives both HTTP and WebSocket traffic. Route both protocol types to the same ChatConsumer.as_asgi() application.

ASGI routing

Edit config/asgi.py:

# config/asgi.py
import os

from django.core.asgi import get_asgi_application
from django.urls import re_path

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
django_app = get_asgi_application()

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator

from chat.consumers import ChatConsumer

socketio_urlpatterns = [
    re_path(r"^socket\.io/?$", ChatConsumer.as_asgi()),
]

application = ProtocolTypeRouter(
    {
        "websocket": AllowedHostsOriginValidator(
            AuthMiddlewareStack(URLRouter(socketio_urlpatterns))
        ),
        "http": AuthMiddlewareStack(
            URLRouter(
                socketio_urlpatterns
                + [
                    # Fallback: send all other HTTP requests to Django.
                    re_path("", django_app),
                ]
            )
        ),
    }
)

Run the server

Run the development server as usual:

python manage.py runserver

Browser client

Use the official Socket.IO JavaScript client. This example connects to the Socket.IO server at /socket.io and then opens the /chat namespace.

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>django-sio chat tutorial</title>
    <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
  </head>
  <body>
    <form id="form">
      <input id="message" autocomplete="off" placeholder="Type a message" />
      <button>Send</button>
    </form>
    <ul id="messages"></ul>

    <script>
      const managerSocket = io("http://localhost:8000", {
        path: "/socket.io",
        transports: ["websocket", "polling"],
      });

      const chat = managerSocket.io.socket("/chat");

      const messages = document.getElementById("messages");
      const form = document.getElementById("form");
      const input = document.getElementById("message");

      function addMessage(text) {
        const item = document.createElement("li");
        item.textContent = text;
        messages.appendChild(item);
      }

      chat.on("connect", () => {
        addMessage("Connected to /chat");
      });

      chat.on("system_message", (payload) => {
        addMessage(`System: ${payload.text}`);
      });

      chat.on("chat_message", (payload) => {
        addMessage(`Chat: ${payload.text}`);
      });

      form.addEventListener("submit", (event) => {
        event.preventDefault();
        const text = input.value;
        input.value = "";

        chat.emit("chat_message", { text }, (ack) => {
          console.log("Ack:", ack);
        });
      });
    </script>
  </body>
</html>

A compact browser example

The same idea can be written without the surrounding HTML:

const socket = io("https://example.com", {
  path: "/socket.io",
  transports: ["websocket", "polling"],
});

const chat = socket.io.socket("/chat");

chat.on("connect", () => {
  console.log("Connected to /chat");
});

chat.on("system_message", (payload) => {
  console.log("System:", payload.text);
});

chat.on("chat_message", (payload) => {
  console.log("Chat:", payload.text);
});

chat.emit("chat_message", { text: "Hello" }, (ack) => {
  console.log("Ack:", ack);
});

In the next part you expand the consumer with room events and acks.