# Mint.WebSocket

[![Coverage Status][coverage-badge]][coverage]
[![ version][hex-version-badge]][hex-package]
[![ license][hex-licence-badge]][licence]
[![Last Updated][last-updated-badge]][commits]

HTTP/1 and HTTP/2 WebSocket support for Mint 🌱

## Usage

`Mint.WebSocket` works together with `Mint.HTTP` API. For example,
this snippet shows sending and receiving a text frame of "hello world" to a
WebSocket server which echos our frames:

# bootstrap
{:ok, conn} = Mint.HTTP.connect(:http, "echo", 9000)

{:ok, conn, ref} = Mint.WebSocket.upgrade(:ws, conn, "/", [])

http_get_message = receive(do: (message -> message))
{:ok, conn, [{:status, ^ref, status}, {:headers, ^ref, resp_headers}, {:done, ^ref}]} =, http_get_message)

{:ok, conn, websocket} =, ref, status, resp_headers)

# send the hello world frame
{:ok, websocket, data} = Mint.WebSocket.encode(websocket, {:text, "hello world"})
{:ok, conn} = Mint.WebSocket.stream_request_body(conn, ref, data)

# receive the hello world reply frame
hello_world_echo_message = receive(do: (message -> message))
{:ok, conn, [{:data, ^ref, data}]} =, hello_world_echo_message)
{:ok, websocket, [{:text, "hello world"}]} = Mint.WebSocket.decode(websocket, data)

Check out some [examples](./examples) and the online [documentation][hex-docs].

## Functional WebSockets

Mint.WebSocket (like Mint) takes a _functional_ approach.
Other WebSocket implementations like
[`:gun`][gun] / [`:websocket_client`][websocket-client] /
[`Socket`][socket] / [`WebSockex`][websockex] work by spawning and
passing messages among processes. This is a very convenient interface in
Erlang and Elixir but it does not allow the author much control over
the WebSocket connection.

Instead `Mint.WebSocket` is process-less: the entire HTTP and WebSocket
states are kept in immutable data structures. When you implement a WebSocket
client with `Mint.WebSocket`, runtime behavior and process architecture
are up to you: you decide how to handle things like reconnection and failures.

For a practical introduction, check out Mint's [usage documentation][mint-usage].

## Spec conformance

This library aims to follow [RFC6455][rfc6455] and [RFC8441][rfc8441] as
closely as possible and uses the [Autobahn|Testsuite][autobahn] to check
conformance with every run of tests/CI. The auto-generated report produced
by the Autobahn|Testsuite is uploaded on each push to main.

See the report here:

## HTTP/2 Support

HTTP/2 WebSockets are not a built-in feature of HTTP/2. In the current
landscape, very few server libraries support the RFC8441's extended CONNECT
method which bootstraps WebSockets.

If `Mint.WebSocket.upgrade/4` returns

{:error, conn, %Mint.WebSocketError{reason: :extended_connect_disabled}}

Then the server does not support HTTP/2 WebSockets or does not have them

## Development workflow

Contributions are very welcome!

If you're interested in developing `Mint.WebSocket`, you'll need docker-compose
to run the fuzzing test suite. The `docker-compose.yml` sets up an Elixir
container, a simple websocket echo server, and the Autobahn|Testsuite fuzzing

(host)$ docker-compose up -d
(host)$ docker-compose exec app bash
(app)$ mix deps.get
(app)$ mix test
(app)$ iex -S mix