Skip to content

WebSocket connections

WebSocket exposes the same API over ASGI and RSGI. Register a handler with Route.websocket(path, action); the connection has converted parameters, headers and its own state. An HTTP GET route at the same path does not replace a WebSocket route.

from orionis.http import WebSocket, WebSocketDisconnected
async def echo(socket: WebSocket) -> None:
await socket.accept()
try:
while True:
value = await socket.receiveJson()
await socket.sendJson({"echo": value})
except WebSocketDisconnected:
return
finally:
await socket.close()

In a route file, import Route from orionis.support.facades and declare Route.websocket("/ws/echo", echo). The handler needs an upgrade-capable server; importing it opens no connections. receiveJson() expects JSON text messages. For binary data use receiveBytes()/sendBytes(), for text use receiveText()/sendText(), or call receive() to inspect a WebSocketMessage and its type.

Place the handler and registration in routes/websocket.py. Create that file if needed, and ensure the existing app.withRouting(...) call in bootstrap/app.py includes websocket="routes/websocket.py", preserving its other arguments. From a page served by the same application, this browser example prints {"echo":{"message":"hello"}}:

const scheme = location.protocol === "https:" ? "wss:" : "ws:";
const socket = new WebSocket(`${scheme}//${location.host}/ws/echo`);
socket.addEventListener("open", () => {
socket.send(JSON.stringify({ message: "hello" }));
});
socket.addEventListener("message", (event) => console.log(event.data));

Close the browser connection with socket.close() when finished. This echo demonstrates transport only; protect private operations before accepting the connection.

Call accept() before sending or receiving application data. Its keyword arguments can select a subprotocol and handshake headers. Reject before acceptance using await socket.reject(status_code=403). After acceptance, terminate with close(code=1000, reason="...") rather than an HTTP response.

accepted, closed and connectionState expose state. supportsCloseDetails identifies transport differences in reporting close reasons and codes. Invalid-state operations and unexpected message kinds raise errors; do not ignore them and continue writing to a closed socket.

WebSocket middleware extends WebSocketMiddleware and receives the connection and a no-argument continuation. Do not attach HTTP response middleware to a socket route. Check access before accept; an allowed origin does not establish identity. The kernel creates a connection context and hubs can use that identity. Long-lived connection state does not replace per-operation authorization when your application needs it.

socket.routeParams() retains route conversions; socket.headers and .state are synchronous. This API has no HTTP form body to read. For typed RPC, groups and correlated results, continue with Realtime.

Bootstrap defaults are 128 connections per worker through WEBSOCKET_MAX_CONNECTIONS and 1 MiB through WEBSOCKET_MAX_MESSAGE_SIZE. The origin policy reads CORS_ALLOW_ORIGINS; without an explicit list WebSocket uses same-origin checks. MCP applies different rules. The kernel rejects excess capacity and cancels connections at shutdown.

Handle WebSocketDisconnected, cancel handler-owned work and await cleanup in finally. Close details vary by server; do not base security decisions on peer-supplied reason text. Connection limits multiply across workers and do not provide distributed admission control.