Search documentation of Phoenix

# Writing a Channels Client

View Source

Client libraries for Phoenix Channels already exist in several languages, but if you want to write your own, this guide should get you started. It may also be useful as a guide for manual testing with a WebSocket client.

## Overview

Because WebSockets are bidirectional, messages can flow in either direction at any time. For this reason, clients typically use callbacks to handle incoming messages whenever they come.

A client must join at least one topic to begin sending and receiving messages, and may join any number of topics using the same connection.

## Connecting

To establish a WebSocket connection to Phoenix Channels, first make note of the `socket` declaration in the application's `Endpoint` module. For example, if you see: `socket "/mobile", MyAppWeb.MobileSocket`, the path for the initial HTTP request is:

    [host]:[port]/mobile/websocket?vsn=2.0.0

Passing `&vsn=2.0.0` specifies `Phoenix.Socket.V2.JSONSerializer`, which is built into Phoenix, and which expects and returns messages in the form of lists.

You also need to include the standard header fields for upgrading an HTTP request to a WebSocket connection or use an HTTP library that handles this for you; in Elixir, mint_web_socket is an example.

Other parameters or headers may be expected or required by the specific `connect/3` function in the application's socket module (in the example above, `MyAppWeb.MobileSocket.connect/3`).

## Message Format

The message format is determined by the serializer configured for the application. For these examples, `Phoenix.Socket.V2.JSONSerializer` is assumed.

The general format for messages a client sends to a Phoenix Channel is as follows:

    [join_reference, message_reference, topic_name, event_name, payload]

- The `join_reference` is also chosen by the client and should also be a unique value. It only needs to be sent for a `"phx_join"` event; for other messages it can be `null`. It is used as a message reference for `push` messages from the server, meaning those that are not replies to a specific client message. For example, imagine something like "a new user just joined the chat room".
- The `message_reference` is chosen by the client and should be a unique value. The server includes it in its reply so that the client knows which message the reply is for.
- The `topic_name` must be a known topic for the socket endpoint, and a client must join that topic before sending any messages on it.
- The `event_name` must match the first argument of a `handle_in` function on the server channel module.
- The `payload` should be a map and is passed as the second argument to that `handle_in` function.

There are three events that are understood by every Phoenix application.

First, `phx_join` is used join a channel. For example, to join the `miami:weather` channel:

    ["0", "0", "miami:weather", "phx_join", {"some": "param"}]

Second, `phx_leave` is used to leave a channel. For example, to leave the `miami:weather` channel:

    [null, "1", "miami:weather", "phx_leave", {}]

Third, `heartbeat` is used to maintain the WebSocket connection. For example:

    [null, "2", "phoenix", "heartbeat", {}]

The `heartbeat` message is only needed when no other messages are being sent and prevents Phoenix from closing the connection; the exact `:timeout` is configured in the application's `Endpoint` module.

Other allowed messages depend on the Phoenix application.

For example, if the Channel serving the `miami:weather` can handle a `report_emergency` event:

    def handle_in("report_emergency", payload, socket) do
      MyApp.Emergencies.report(payload) # or whatever
      {:reply, :ok, socket}
    end

...a client could send:

    [null, "3", "miami:weather", "report_emergency", {"category": "sharknado"}]

← Previous Page Using SSL