Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/maartenvanvliet/subscriptions-transport-ws
Socket library implementation of the subscriptions-transport-ws graphql subscription protocol for Absinthe
https://github.com/maartenvanvliet/subscriptions-transport-ws
Last synced: 28 days ago
JSON representation
Socket library implementation of the subscriptions-transport-ws graphql subscription protocol for Absinthe
- Host: GitHub
- URL: https://github.com/maartenvanvliet/subscriptions-transport-ws
- Owner: maartenvanvliet
- License: mit
- Created: 2021-03-04T22:19:48.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2023-03-03T04:58:50.000Z (almost 2 years ago)
- Last Synced: 2024-09-19T16:36:20.638Z (3 months ago)
- Language: Elixir
- Size: 129 KB
- Stars: 23
- Watchers: 4
- Forks: 1
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# SubscriptionsTransportWS
## [![Hex pm](http://img.shields.io/hexpm/v/subscriptions_transport_ws.svg?style=flat)](https://hex.pm/packages/subscriptions_transport_ws) [![Hex Docs](https://img.shields.io/badge/hex-docs-9768d1.svg)](https://hexdocs.pm/subscriptions_transport_ws) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)![.github/workflows/elixir.yml](https://github.com/maartenvanvliet/subscriptions-transport-ws/workflows/.github/workflows/elixir.yml/badge.svg)
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/ Apollo JS and Urql with subscriptions-transport-ws.
## Subscriptions-Transport-WS vs Graphql-WS
`subscriptions-transport-ws` is an older [protocol](https://github.com/apollographql/subscriptions-transport-ws). A newer one has been written named [graphql_ws](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md). The grapqhl_ws protocol is more robust, and the way to go in the future.At the time of writing the major libraries support one, the other or both. E.g. Apollo Swift currently [only supports](https://github.com/apollographql/apollo-ios/issues/1622#issuecomment-892189145) `subscriptions-transport-ws`, v3 of Apollo Android supports `graphql_ws`. The Urlq/Apollo JS libraries support either one.
If you need to support `graphql_ws` on the backend in Elixir, you can use the [absinthe_graphql_ws](https://github.com/geometerio/absinthe_graphql_ws) library. You can set up multiple websocket endpoints to support both protocols.
## Installation
The package can be installed by adding `subscriptions_transport_ws` to your list of dependencies in `mix.exs`:
```elixir
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:
```elixir
config :my_app, MyAppWeb.Endpoint,
# ... other config
pubsub_server: MyApp.PubSub
```
In your application supervisor add a line AFTER your existing endpoint supervision line:```elixir
[
# 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`
```elixir
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:
```elixir
defmodule MyAppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
use Absinthe.Phoenix.Endpointsocket("/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 Apollo JS
```javascript
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
useSubscription,
} from "@apollo/client";
import { split, HttpLink } from "@apollo/client";
import { getMainDefinition } from "@apollo/client/utilities";
import { WebSocketLink } from "@apollo/client/link/ws";const wsLink = new WebSocketLink({
uri: "ws://localhost:4000/absinthe-ws/websocket",
options: {
reconnect: true,
},
});
const httpLink = new HttpLink({
uri: "http://localhost:4000/api",
});const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
wsLink,
httpLink
);const client = new ApolloClient({
uri: "http://localhost:4000/api",
cache: new InMemoryCache(),
link: splitLink,
});
```See the [Apollo documentation](https://www.apollographql.com/docs/react/data/subscriptions/) for more information
## Example with Urql
```javascript
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](https://formidable.com/open-source/urql/docs/advanced/subscriptions/#setting-up-subscriptions-transport-ws) for more information.## Example with Swift Apollo
```swift
import Apollo
import ApolloSQLite
import ApolloWebSocket
import Foundation
import Combineclass ApolloService {
static let shared = ApolloService()
static let url = Config.host.appendingPathComponent("api")
private(set) lazy var client: ApolloClient = {let store = ApolloStore()
let requestChainTransport = RequestChainNetworkTransport(
interceptorProvider: DefaultInterceptorProvider(store: store),
endpointURL: "https://localhost:4000/api"
)
// The Normal Apollo Web Socket Implementation which uses an Apollo adapter server side
let wsUrl = "wss://localhost:4000/absinthe-ws/websocket"
let wsRequest = URLRequest(url: wsUrl)
let wsClient = WebSocket(request: wsRequest)
let apolloWebSocketTransport = WebSocketTransport(websocket: wsClient)let splitNetworkTransport = SplitNetworkTransport(
uploadingNetworkTransport: requestChainTransport,
webSocketNetworkTransport: apolloWebSocketTransport
)// Remember to give the store you already created to the client so it
// doesn't create one on its own
let client = ApolloClient(
networkTransport: splitNetworkTransport,
store: store
)return client
}()
}
```Or see here https://www.apollographql.com/docs/ios/subscriptions/#subscriptions-and-authorization-tokens
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/subscriptions_transport_ws](https://hexdocs.pm/subscription_transport_ws).