lilydocs
HTTP APIWebSocketConsumer
Getting started3 min read

Your first client

Open a Lily v2 connection from the browser, send your first event, and track ACK identifiers.

After running the first server, you can connect from the browser. The address, namespace, subprotocol, and envelope expected by the server work together.

Connect from the browser#

Run the following code in the console of a page at http://localhost:3000. You can use this documentation's local preview if it runs at that address; if you use another Origin, also change allowed_origins on the server.

browser-client.js
const socket = new WebSocket(
  "ws://127.0.0.1:8081/ws?namespace=hello",
  "lily.v2",
);

socket.addEventListener("message", ({ data }) => {
  console.log(JSON.parse(data));
});
socket.addEventListener("close", ({ code, reason }) => {
  console.log("Bağlantı kapandı", code, reason);
});
socket.addEventListener("open", () => {
  socket.send(JSON.stringify({
    protocol_version: 2,
    msg_type: "event",
    event: "hello:greet",
    content_kind: "json",
    content_type: "application/json",
    encoding: "identity",
    data: { name: "Ada" },
    namespace: "hello",
    timestamp: Date.now(),
  }));
});

// Run after the connection becomes OPEN:
function requestConfirmation() {
  const ackId = crypto.randomUUID();
  socket.send(JSON.stringify({
    protocol_version: 2,
    msg_type: "event",
    event: "hello:confirm",
    content_kind: "json",
    content_type: "application/json",
    encoding: "identity",
    data: { name: "Ada" },
    ack_id: ackId,
    timestamp: Date.now(),
  }));
  return ackId;
}

Download the client file. The open event starts the first send; call requestConfirmation() after the connection opens. Do not use send in the CONNECTING state.

Read the response#

The response to the first message has msg_type equal to event, event equal to hello:greeted, and data equal to Merhaba, Ada!. The response to requestConfirmation() has msg_type equal to ack, with an ack_id matching the ID returned by the function.

This small example logs responses to the console. An application client needs a pending-request table, timeouts, error mapping, and completion of pending requests when the connection closes. Define an operation's idempotency contract before resending it after reconnecting. The Rust client provides request/ACK correlation.

Namespace and time#

The namespace is selected at connection startup with ?namespace=hello. The event still carries the full hello:greet name. If the optional envelope namespace field is present, it must match the connection; you cannot switch namespaces in the next message.

timestamp is message metadata supplied by the client. It is not the server's monotonic processing deadline or proof of a trusted clock. The envelope reference also explains text and binary content types.

CLI and service clients#

Explicitly change the policy for clients that do not send an Origin:

ServerConfig snippet
use lilyrs::websocket::ServerConfig;
let policy = ServerConfig {
    allow_missing_origin: true,
    require_subprotocol: true,
    ..ServerConfig::default()
};

This option does not accept an Origin that is present but disallowed. The browser's WebSocket constructor accepts a URL and a subprotocol list; it has no arbitrary Authorization header option. The header-based authentication example is for service/CLI clients. In browsers, follow the cookie/session approach. This distinction follows the WebSocket standard's interface.

Sources for this page v0.1.0

This guide is based on the reviewed framework commit.

QUICK START
Documentation
Source code