SubscriptionsTransportWS.Socket behaviour (SubscriptionsTransportWS v1.0.0) View Source
Implementation of the subscriptions-transport-ws graphql subscription protocol for Absinthe. Instead of using Absinthe subscriptions over Phoenix channels it exposes a websocket directly. This allows you to use
the Apollo and Urql Graphql clients without using a translation layer to Phoenix channels such as @absinthe/socket
.
Has been tested with Apollo iOS and Urql with subscriptions-transport-ws.
Installation
If available in Hex, the package can be installed
by adding subscriptions_transport_ws
to your list of dependencies in mix.exs
:
def deps do
[
{:subscriptions_transport_ws, "~> 1.0.0"}
]
end
Usage
There are several steps to use this library.
You need to have a working phoenix pubsub configured. Here is what the default looks like if you create a new phoenix project:
config :my_app, MyAppWeb.Endpoint,
# ... other config
pubsub_server: MyApp.PubSub
In your application supervisor add a line AFTER your existing endpoint supervision line:
[
# other children ...
MyAppWeb.Endpoint, # this line should already exist
{Absinthe.Subscription, MyAppWeb.Endpoint}, # add this line
# other children ...
]
Where MyAppWeb.Endpoint is the name of your application's phoenix endpoint.
Add a module in your app lib/web/channels/absinthe_socket.ex
defmodule AbsintheSocket do
# App.GraphqlSchema is your graphql schema
use SubscriptionsTransportWS.Socket, schema: App.GraphqlSchema, keep_alive: 1000
# Callback similar to default Phoenix UserSocket
@impl true
def connect(params, socket) do
{:ok, socket}
end
# Callback to authenticate the user
@impl true
def gql_connection_init(message, socket) do
{:ok, socket}
end
end
In your MyAppWeb.Endpoint module add:
defmodule MyAppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
use Absinthe.Phoenix.Endpoint
socket("/absinthe-ws", AbsintheSocket, websocket: [subprotocols: ["graphql-ws"]])
# ...
end
Now if you start your app you can connect to the socket on ws://localhost:4000/absinthe-ws/websocket
Example with Urql
import { SubscriptionClient } from "subscriptions-transport-ws";
import {
useSubscription,
Provider,
defaultExchanges,
subscriptionExchange,
} from "urql";
const subscriptionClient = new SubscriptionClient(
"ws://localhost:4000/absinthe-ws/websocket",
{
reconnect: true,
}
);
const client = new Client({
url: "http://localhost:4000/api",
exchanges: [
subscriptionExchange({
forwardSubscription(operation) {
return subscriptionClient.request(operation);
},
}),
...defaultExchanges,
],
});
See the Urql documentation for more information.
Example with Swift
See here https://www.apollographql.com/docs/ios/subscriptions/#subscriptions-and-authorization-tokens
Link to this section Summary
Functions
Adds key value pairs to socket assigns. A single key value pair may be passed, a keyword list or map of assigns may be provided to be merged into existing socket assigns.
Adds key-value pairs into Absinthe context.
Same as assign_context/2
except one key-value pair is assigned.
Default pipeline to use for Absinthe graphql document execution
Sets the options for a given GraphQL document execution.
Callbacks
Receives the socket params and authenticates the connection.
Callback for the connection_init
message.
The client sends this message after plain websocket connection to start
the communication with the server.
Link to this section Types
Specs
t() :: %SubscriptionsTransportWS.Socket{ assigns: map(), endpoint: atom(), handler: atom(), json_module: atom(), keep_alive: integer() | nil, operations: map(), pubsub_server: atom(), serializer: atom() }
When using this module there are several options available
json_module
- defaults to Jasonschema
- refers to the Absinthe schema (required)pipeline
- refers to the Absinthe pipeline to use, defaults to{SubscriptionsTransportWS.Socket, :default_pipeline}
keep_alive
period in ms to send keep alive messages over the socket, defaults to 10000
Example
use SubscriptionsTransportWS.Socket, schema: App.GraphqlSchema, keep_alive: 1000
Link to this section Functions
Adds key value pairs to socket assigns. A single key value pair may be passed, a keyword list or map of assigns may be provided to be merged into existing socket assigns.
Examples
iex> assign(socket, :name, "Elixir")
iex> assign(socket, name: "Elixir", logo: "💧")
Adds key-value pairs into Absinthe context.
Examples
iex> Socket.assign_context(socket, current_user: user)
%Socket{}
Same as assign_context/2
except one key-value pair is assigned.
Default pipeline to use for Absinthe graphql document execution
Sets the options for a given GraphQL document execution.
Examples
iex> SubscriptionsTransportWS.Socket.put_options(socket, context: %{current_user: user})
%SubscriptionsTransportWS.Socket{}
Link to this section Callbacks
Specs
Receives the socket params and authenticates the connection.
Socket params and assigns
Socket params are passed from the client and can be used to verify and authenticate a user. After verification, you can put default assigns into the socket that will be set for all channels, ie
{:ok, assign(socket, :user_id, verified_user_id)}
To deny connection, return :error
.
See Phoenix.Token
documentation for examples in
performing token verification on connect.
Specs
Specs
Callback for the connection_init
message.
The client sends this message after plain websocket connection to start
the communication with the server.
In the subscriptions-transport-ws
protocol this is usually used to
set the user on the socket.
Should return {:ok, socket}
on success, and {:error, payload}
to deny.
Receives the a map of connection_params
, see
- connectionParams in Apollo javascript client
- connectingPayload in Apollo iOS client
or similar in other clients.