A Phoenix Channels specification library for automatic data validation and schema generation inspired by OpenAPI and built on top of ChannelHandler.
You can install ChannelSpec from git, and ChannelHandler from Hex:
def deps do
  [
    {:channel_handler, "~> 0.6"},
    {:channel_spec, github: "felt/channel_spec"}
  ]
endFirst, you need to define the Phoenix Socket module by using ChannelSpec.Socket:
defmodule MyAppWeb.UserSocket do
  use ChannelSpec.Socket
  channel "room:*", MyAppWeb.RoomChannel
endThen, you must define the channel module. For this, you have to use three modules:
Phoenix.Channelfor basic Channel functionalityChannelHandler.Routerto define the event routingChannelSpec.Operationsto define operation schemas
defmodule MyAppWeb.RoomChannel do
  use Phoenix.Channel
  use ChannelHandler.Router
  use ChannelSpec.Operations
  join fn _topic, _payload, socket ->
    {:ok, socket}
  end
  operation "new_msg",
    payload: %{
      type: :object,
      properties: %{text: %{type: :string}}
    },
    replies: %{
      ok: %{type: :string},
      error: %{type: :string}
    }
  handle "new_msg", fn %{"text" => text}, _context, socket ->
    {:reply, {:ok, text}, socket}
  end
endThis will tell ChannelSpec that the server is capable of receiving a "new_msg" event,
with a map with a key text of type string and that it will reply with a string both
in case of success and error.
By using ChannelSpec, the following features will be available:
- A schema file can be automatically generated by passing the 
:schema_pathoption touse ChannelSpec.Socket - Using 
plug ChannelSpec.Plugs.ValidateInputwill allow you to validate incoming payloads against your operation schemas mix channelspec.routes MyAppWeb.Endpointto list all available events and their handlers, as defined withChannelHandler.Router. Passing the--verboseflag will also include file:line information about the files where the operation and the handler function are defined.- Testing that reply values conform to spec with 
ChannelSpec.Testing.assert_reply_spec 
If you add plug ChannelSpec.Plugs.ValidateInput to your channel or handler modules, the incoming message
payloads will be validated against your schemas. In case of a validation error, an error will immediately
be returned to the client.
You can configure the socket module to generate a schema file, that can be used to generate bindings for client code or documentation:
defmodule MyAppWeb.UserSocket do
  use ChannelSpec.Socket, schema_path: "priv/schema.json"
endYou can use ChannelSpec's enhanced test helpers to verify the channel replies conform to the specified schemas:
defmodule MyAppWeb.RoomChannelTest do
  use ExUnit.Case, async: true
  use ChannelSpec.Testing
  setup do
    {:ok, _, socket} =
      MyAppWeb.UserSocket
      |> socket("123", %{})
      |> subscribe_and_join(MyAppWeb.RoomChannel, "room:123")
    %{socket: socket}
  end
  test "returns a valid reply", %{socket: socket} do
    # Send a number body instead of a string
    ref = push(socket, "new_msg", %{body: 123}
    assert_reply_spec ref, :ok, reply # Will raise a validation error!
    assert is_binary(reply)
  end
endYou can use the generate schema file to generate client bindings. For Typescript bindings, you can use the companion channel_spec_tscodegen tool.