Are you aware that in order to run Apollo subscription, GraphQL server should implement GraphQL over WebSocket Protocol?

Previously I worked with GraphQL servers that implement this protocol such as : Node server uses subscriptions-transport-ws, Elixir server with absinthe-socket and I integrated them with VanillaJS, React and Angular front-ends. No problem!

Recently I got a requirement to consume a subscription from Scala GraphQL implementation — sangria. It turned out that it is possible to implement WebSocket subscription in sangria (see sangria-subscriptions-example branch https://github.com/sangria-graphql/sangria-subscriptions-example/tree/trbngr-websockets) but GraphQL WebSocket protocol is not implemented and Apollo Subscription won’t work.

Since I did not have any choice but integrate I had to implement a simple WebSocket Apollo Link for subscription. The full client code you can find at Github sangria-apollo-websocket-example and server code is at https://github.com/sangria-graphql/sangria-subscriptions-example/tree/trbngr-websockets

Basic Apollo WebSocket Link

Here is the basic Apollo client setup with http and subscription link. WebSocketBasicLink function will create a basic web socket link. I won’t go in details about this setup since it is the standard Apollo code.

function createSangriaLink() {

return new WebSocketBasicLink({ uri: "ws://localhost:8080/graphql" });

}



const wsLink = createSangriaLink();

const link = split(

({ query }) => {

const { kind, operation } = getMainDefinition(query);

return kind === "OperationDefinition" && operation === "subscription";

},

wsLink,

createHttpLink({ uri: "http://localhost:8080/graphql" })

);



const client = new ApolloClient({

link: link,

cache: new InMemoryCache()

});

Let’s implement WebSocketBasicLink. As any Apollo links it should extends ApolloLink class. To work with WebSocket I used RxJs webSocket subject. You can read my blog about RxJS and WebSocket implementation at WebSocket error handling with RxJS

Here it is:

class WebSocketBasicLink extends ApolloLink {

constructor({ uri }) {

super();



this.requester = operation => {

return new LinkObservable(observer => {

const query = print(operation.query);

const subject = webSocket(uri);

subject.next({ query });



const sub = subject.subscribe(

data => observer.next(data),

error => observer.error(error),

() => observer.complete()

);



return () => {

if (!sub.closed) {

sub.unsubscribe();

}

};

});

};

}



request(op) {

return this.requester(op);

}

}

Let’s test it

Now we are ready to run the solution. We will use:

GraphiQL can be used to send new data to the Sangria server:

2. The created above Apollo client to subscribe to receive the events via WebSocket.

const query = `

subscription NewAuthors {

authorCreated {

id

version

firstName

lastName

}

}

`; client.subscribe({

query: gql`

${query}

`,

fetchPolicy: "no-cache"

})

).subscribe(msg => {

console.log(msg);

});

3. Chrome Inspect -> Network ->WS to monitor webSocket traffic. You can observer the messages that the client and server pass to each other.

Hyperapp

The solution is working and as a bonus I decided to add simple UI to display messages and control the subscription. I use React and Angular everyday, so I wanted to try something else. After a quick research I found an interesting framework to experiment for my simple UI — hyperapp. At this moment they are in active development of the V2 (https://github.com/jorgebucaran/hyperapp/pull/726) of the framework with effects, actions and subscriptions API. Subscription this is what I needed for my task. Plus hyperapp looks similar to Elm and allow to use JSX for view.

In 15 mins my UI got ready.

Here is HyperApp subscription with effect that adds received message to a collection to display. If you have experience with NGRX or redux-observable these terms will be familiar to you.