WebsockexNova.ClientMacro (WebsockexNova v0.1.0)
View SourceMacro for building WebsockexNova client modules with minimal boilerplate.
This macro provides a convenient way to create domain-specific WebSocket client modules that wrap the generic WebsockexNova.Client with service-specific functionality.
Basic Usage
defmodule MyApp.MyClient do
use WebsockexNova.ClientMacro, adapter: MyApp.MyAdapter
# Add domain-specific methods:
def subscribe_to_custom_channel(conn, instrument_id, opts \ nil) do
channel = "custom.#{instrument_id}.events"
subscribe(conn, channel, opts)
end
end
What this macro does
- Injects all common client functions (connect, authenticate, send_json, subscribe, etc.)
- Configures the client to use your specified adapter
- Provides default connection options that can be overridden
- Enables dependency injection for testing via application config
- Allows you to add domain-specific helper methods
Options
:adapter
(required) - The adapter module to use for connections:default_options
(optional) - Default connection options as a map
Examples
Trading client with custom methods
defmodule MyApp.TradingClient do
use WebsockexNova.ClientMacro,
adapter: MyApp.TradingAdapter,
default_options: %{
heartbeat_interval: 10_000,
reconnect_delay: 1_000
}
def place_order(conn, order_params) do
send_json(conn, %{
method: "place_order",
params: order_params
})
end
def subscribe_to_orderbook(conn, symbol, depth \ 10) do
subscribe(conn, "orderbook.#{symbol}", %{depth: depth})
end
def subscribe_to_trades(conn, symbol) do
subscribe(conn, "trades.#{symbol}", %{})
end
end
# Usage:
{:ok, conn} = MyApp.TradingClient.connect()
{:ok, _} = MyApp.TradingClient.authenticate(conn, %{api_key: "key", api_secret: "secret"})
{:ok, _} = MyApp.TradingClient.subscribe_to_orderbook(conn, "BTC-USD")
Chat client with typed message sending
defmodule MyApp.ChatClient do
use WebsockexNova.ClientMacro,
adapter: MyApp.ChatAdapter
def send_chat_message(conn, room_id, message) do
send_json(conn, %{
type: "message",
room: room_id,
text: message,
timestamp: DateTime.utc_now()
})
end
def join_room(conn, room_id) do
send_json(conn, %{type: "join", room: room_id})
end
def leave_room(conn, room_id) do
send_json(conn, %{type: "leave", room: room_id})
end
def set_typing_status(conn, room_id, is_typing) do
send_json(conn, %{
type: "typing",
room: room_id,
typing: is_typing
})
end
end
IoT client with device management
defmodule MyApp.IoTClient do
use WebsockexNova.ClientMacro,
adapter: MyApp.IoTAdapter,
default_options: %{
transport: :tcp,
port: 8883,
protocol: "mqtt-websocket"
}
def register_device(conn, device_id, metadata) do
send_json(conn, %{
action: "register",
device_id: device_id,
metadata: metadata
})
end
def send_telemetry(conn, device_id, data) do
send_json(conn, %{
action: "telemetry",
device_id: device_id,
data: data,
timestamp: System.system_time(:second)
})
end
def update_device_shadow(conn, device_id, desired_state) do
send_json(conn, %{
action: "update_shadow",
device_id: device_id,
state: %{desired: desired_state}
})
end
end
Testing Support
The macro supports dependency injection for testing by allowing you to configure the underlying client module:
# In config/test.exs
config :websockex_nova, :client_module, MyApp.MockClient
# In your test
defmodule MyApp.TradingClientTest do
use ExUnit.Case
test "places order successfully" do
{:ok, conn} = MyApp.TradingClient.connect()
{:ok, response} = MyApp.TradingClient.place_order(conn, %{symbol: "BTC-USD", size: 1})
assert response.order_id
end
end
Available Functions
The following functions are automatically available in your client module:
connect/0
,connect/1
- Establish WebSocket connectionclose/1
- Close connectionping/1
- Send ping framesend_text/2
- Send text messagesend_json/2
- Send JSON-encoded messagesend_binary/2
- Send binary messagesend_frame/3
- Send specific frame typesend_message/2
- Send via message handlersubscribe/3
- Subscribe to channelunsubscribe/2
- Unsubscribe from channelauthenticate/2
- Perform authentication
Tips
- Keep domain logic in your client module, not in the adapter
- Use typed functions for common operations (like
subscribe_to_trades/2
) - Consider adding error handling in your domain-specific methods
- Use default_options for environment-specific configuration
- Document your domain-specific methods for better usability
See WebsockexNova.Examples.ClientDeribitMacro
for a complete example.