Skip to content

Instantly share code, notes, and snippets.

@djstein
Created June 17, 2020 17:59
Show Gist options
  • Save djstein/2005ba638ec1dd59f74cb86f8a0f3ef3 to your computer and use it in GitHub Desktop.
Save djstein/2005ba638ec1dd59f74cb86f8a0f3ef3 to your computer and use it in GitHub Desktop.
a useSubscription Hook for Apollo Server when you hate Apollo Client
import { print } from 'graphql/language/printer'
import { useContext, useEffect, useState } from 'react'
export function createWebsocket({ name, uri, token, query, onMessage }) {
if (!uri) {
let subscriptionProtocol = process.env.REACT_APP_API_URL.includes(
'https',
)
? 'wss'
: 'ws'
uri = `${subscriptionProtocol}://${
process.env.REACT_APP_API_URL.split('://')[1]}`
}
const socket = new WebSocket(uri, ['graphql-ws'])
socket.onopen = (event) => {
console.info(`Opening ${name} WebSocket`, event)
socket.send(
JSON.stringify({
payload: {
authorization: `Bearer ${token}`,
headers: {
Authorization: `Bearer ${token}`,
},
},
type: 'connection_init',
}),
)
socket.send(
JSON.stringify({
id: '1',
type: 'start',
payload: {
variables: {},
extensions: {},
operationName: query.definitions[0].name.value,
query: print(query),
},
}),
)
}
socket.onmessage = (messageEvent) => {
let data = JSON.parse(messageEvent.data)?.payload?.data?.[
query.definitions[0].selectionSet.selections[0].name.value
]
if (data && onMessage) {
onMessage(data)
}
}
socket.onclose = (closeEvent) => {
if (process.env.NODE_ENV !== 'test') {
console.info(`Closing ${name} WebSocket`, closeEvent)
}
}
socket.onerror = (event) => {
if (process.env.NODE_ENV !== 'test') {
console.error(`Error ${name} WebSocket`, event)
throw new Error(event)
}
}
return socket
}
export default function useSubscription(options) {
const { authToken } = useContext(AuthContext)
let [socket, setSocket] = useState()
if (!options?.token) {
options.token = authToken
}
useEffect(
() => {
if (process.env.REACT_APP_BUILD_ENV !== 'integration') {
setSocket(createWebsocket(options))
}
return () => {
if (process.env.NODE_ENV !== 'test') {
console.info(`Unmount Closing ${options?.name} WebSocket`)
}
try {
if (socket) {
socket.close()
}
} catch (exception) {
console.error('Socket already closed.', exception)
}
}
}, // eslint-disable-next-line react-hooks/exhaustive-deps
[],
)
return socket
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment