Skip to content

Instantly share code, notes, and snippets.

@jedwards1211
Created January 15, 2020 17:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jedwards1211/f17ca8116f22bd54a3f3d1227b6e6005 to your computer and use it in GitHub Desktop.
Save jedwards1211/f17ca8116f22bd54a3f3d1227b6e6005 to your computer and use it in GitHub Desktop.
installSubscriptionHandlers workaround
/**
* @flow
* @prettier
*/
import { ApolloServer } from 'apollo-server-express'
import { typeof Server as HttpServer } from 'http'
import WebSocket from 'ws'
import { SubscriptionServer } from 'subscriptions-transport-ws'
import { formatApolloErrors } from 'apollo-server-errors'
import { execute, subscribe, type ExecutionResult } from 'graphql'
/**
* This is a fork of ApolloServer.installSubscriptionHandlers that allows us
* to pass a WebSocket.Server as a workaround for the WebSocket created by
* ApolloServer aborting the handshake for the Meteor DDP WebSocket.
*/
export function installSubscriptionHandlers(server: HttpServer | WebSocket.Server): SubscriptionServer {
if (!this.subscriptionServerOptions) {
if (this.supportsSubscriptions()) {
throw Error('Subscriptions are disabled, due to subscriptions set to false in the ApolloServer constructor')
} else {
throw Error(
'Subscriptions are not supported, choose an integration, such as apollo-server-express that allows persistent connections'
)
}
}
const { onDisconnect, onConnect, keepAlive, path } = this.subscriptionServerOptions
return (this.subscriptionServer = SubscriptionServer.create(
{
schema: this.schema,
execute,
subscribe,
onConnect: onConnect ? onConnect : (connectionParams: Object) => ({ ...connectionParams }),
onDisconnect,
onOperation: async (message: { payload: any }, connection: any) => {
connection.formatResponse = (value: ExecutionResult) => ({
...value,
errors:
value.errors &&
formatApolloErrors([...value.errors], {
formatter: this.requestOptions.formatError,
debug: this.requestOptions.debug,
}),
})
let context = this.context ? this.context : { connection }
try {
context =
typeof this.context === 'function' ? await this.context({ connection, payload: message.payload }) : context
} catch (e) {
throw formatApolloErrors([e], {
formatter: this.requestOptions.formatError,
debug: this.requestOptions.debug,
})[0]
}
return { ...connection, context }
},
keepAlive,
},
server instanceof WebSocket.Server
? server
: {
server,
path,
}
))
}
export default function createServer(options): ApolloServer {
// I used Object.create here because I was getting "constructor must be called
// with new" type errors when I tried extending the ApolloServer class, even
// though I was using new. I guess it's something to do with extending classes
// from TypeScript.
return Object.create(
new ApolloServer(options),
{
installSubscriptionHandlers: {
value: installSubscriptionHandlers,
},
}
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment