A small, typed WebSocket client for Elm with a compact, auditable JavaScript runtime. It supports multiple connections, lifecycle events, and text, binary, or JSON messages.
Install the Elm package:
elm install mbr/elm-wssElm packages cannot declare ports. Make Main.elm a port module, or use another application-owned port module, then add these declarations:
import WebsocketSimple exposing (CommandPort, EventPort)
port wsCmd : CommandPort msg
port wsMsg : EventPort msgThe JavaScript runtime expects the exact port names wsCmd and wsMsg.
Copy js/elm-websockets.js into the browser assets. Load the runtime and compiled Elm application, initialize Elm, and then initialize the runtime:
<script src="elm-websockets.js"></script>
<script src="app.js"></script>
<script>
var app = Elm.Main.init({
node: document.getElementById("elm")
});
ElmWebsockets.initApp(app);
</script>The JavaScript initialization is a no-op when the application does not contain the command port, so it can remain in the bootstrap while WebSocket code is temporarily unused.
Pass the application-owned ports described by these aliases to commands and subscriptions.
Type of an application-owned port that receives encoded events from the JavaScript runtime.
Subscribe to events before opening a connection, and wait for Connected before transmitting:
import WebsocketPorts as Ports
import WebsocketSimple as WebSocket
type Msg
= WebSocketEvent WebSocket.RawMsg
init : () -> ( List String, Cmd Msg )
init _ =
( [], WebSocket.open Ports.wsCmd "ws://127.0.0.1:8765" )
update : Msg -> List String -> ( List String, Cmd Msg )
update msg model =
case msg of
WebSocketEvent (WebSocket.Connected _) ->
( model, WebSocket.send Ports.wsCmd (WebSocket.Transmit "hello") )
WebSocketEvent (WebSocket.Text value) ->
( value :: model, WebSocket.close Ports.wsCmd )
WebSocketEvent (WebSocket.Binary _) ->
( model, WebSocket.close Ports.wsCmd )
WebSocketEvent (WebSocket.Disconnected _) ->
( model, Cmd.none )
WebSocketEvent (WebSocket.TransportError error) ->
( WebSocket.errorToString error :: model, Cmd.none )
subscriptions : List String -> Sub Msg
subscriptions _ =
Sub.map WebSocketEvent (WebSocket.subscribe Ports.wsMsg)send and its convenience functions use an implicit "default" handle. Use sendWithHandle for multiple connections.
Command sent to a WebSocket connection.
Open opens the URL with an ordered list of requested subprotocols. An empty list requests none.Transmit sends a text frame.TransmitBinary sends a binary frame.TransportError; an accepted transmission produces no acknowledgement.Close Nothing preserves the browser's default close behavior. Close (Just request) sends the supplied code and reason unchanged, leaving validation to the browser.Describes an application-requested close.
Use an empty reason to send only the explicit close code.
Open the implicit default connection without requesting a subprotocol.
Close the implicit default connection with the browser's default status.
Send a command to the connection identified by a handle.
Each connection is identified by an opaque handle encoded as a string at the port boundary.
chat : WebSocket.Handle
chat =
WebSocket.handle "chat"
alerts : WebSocket.Handle
alerts =
WebSocket.handle "alerts"
openConnections : Cmd msg
openConnections =
Cmd.batch
[ WebSocket.sendWithHandle Ports.wsCmd chat (WebSocket.Open chatUrl [])
, WebSocket.sendWithHandle Ports.wsCmd alerts (WebSocket.Open alertsUrl [])
]Identifies a particular WebSocket connection.
Return a WebSocket handle's string representation.
subscribe discards handle information. Use subscribeWithHandle to distinguish events from multiple connections.
type Msg
= WebSocketEvent ( WebSocket.Handle, WebSocket.RawMsg )
subscriptions : model -> Sub Msg
subscriptions _ =
Sub.map WebSocketEvent (WebSocket.subscribeWithHandle Ports.wsMsg)Raw event received from a WebSocket connection.
Connected means the connection can transmit and contains the negotiated subprotocol, if any.Disconnected contains the browser's close details and may occur without a preceding Connected event.Text contains a received text frame.Binary contains a received binary frame.TransportError describes a construction, send, close, browser, unsupported-data, or port-decoding failure.Events preserve browser delivery order even though binary reads are asynchronous.
Details supplied when a WebSocket closes.
The event may arrive even when the connection never opened. initiatedLocally records whether this client successfully requested closure.
Categorizes a WebSocket transport error.
Describes a categorized WebSocket transport error.
Subscribe to raw events from the implicit default connection.
This discards the originating handle from every event.
Subscribe to raw events paired with their originating handles.
Render a transport error category as a string.
Render a transport error as a readable string containing its category and message.
Regular subscriptions expose incoming text and binary frames as Text String and Binary Bytes. Typed subscriptions decode text frames while keeping transport errors separate from payload decoding failures. A binary frame received through a typed JSON subscription produces an UnsupportedData transport failure.
import Json.Decode as Decode
type alias Payload =
{ message : String }
payloadDecoder : Decode.Decoder Payload
payloadDecoder =
Decode.map Payload (Decode.field "message" Decode.string)
type Msg
= WebSocketMessage (WebSocket.Msg Payload)
subscriptions : model -> Sub Msg
subscriptions _ =
WebSocket.subscribeMsg Ports.wsMsg payloadDecoder WebSocketMessageTyped event received from a WebSocket connection carrying JSON text frames.
Transport failures remain separate from payload decoding failures. PayloadDecodeFailure retains both the original text and the Json.Decode.Error.
Subscribe to typed JSON events while discarding handle information.
Subscribe to typed JSON events paired with their originating handles.
Encode a value as JSON and transmit it through the implicit default connection.
Encode a value as JSON and transmit it through the connection identified by a handle.
Convert a raw event into a typed JSON event.
Type of an application-owned port that sends encoded commands to the JavaScript runtime.