Skip to content

Instantly share code, notes, and snippets.

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 timkock/b38ae86cf5634c63dc482c7fc1c66be1 to your computer and use it in GitHub Desktop.
Save timkock/b38ae86cf5634c63dc482c7fc1c66be1 to your computer and use it in GitHub Desktop.
/* eslint-disable no-param-reassign */
/* eslint-disable object-curly-newline */
// requirements
const ws = require('ws');
const { SubscriptionServer } = require('subscriptions-transport-ws');
const { formatApolloErrors } = require('apollo-server-errors');
const { execute, subscribe } = require('graphql');
// export patch
function installSubscriptionHandlers(server) {
if (!this.subscriptionServerOptions) {
if (this.config.gateway) {
throw Error('Subscriptions are not supported when operating as a gateway');
}
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;
const { schema } = this;
if (this.schema === undefined) throw new Error('Schema undefined during creation of subscription server.');
this.subscriptionServer = SubscriptionServer.create({
schema,
execute,
subscribe,
onConnect: onConnect || ((connectionParams) => ({ ...connectionParams })),
onDisconnect,
onOperation: async (message, connection) => {
connection.formatResponse = (value) => ({
...value,
errors: value.errors
&& formatApolloErrors([...value.errors], {
formatter: this.requestOptions.formatError,
debug: this.requestOptions.debug,
}),
});
connection.formatError = this.requestOptions.formatError;
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,
validationRules: this.requestOptions.validationRules,
}, server instanceof ws.Server
? server
: {
server,
path,
});
}
module.exports = installSubscriptionHandlers;
@timkock
Copy link
Author

timkock commented Aug 13, 2020

TODO: keep eye on apollo-server release 3.0, that hopefully mitigates this problem

After creating an instance of ApolloServer

const server = new ApolloServer({});

You can just monkey-patch the installSubscriptionHandlers function as such:

const installSubscriptionHandlers = require('./patch/ApolloServer.installSubscriptionHandlers');
server.installSubscriptionHandlers = installSubscriptionHandlers;

@gregbarcza
Copy link

Typescript version

Changes made:

  • use import instead of require
  • ignore errors for any (alias this as that, disable ts compiler for line 14)
/* eslint-disable no-param-reassign */
/* eslint-disable object-curly-newline */

// requirements
import * as ws from 'ws'
import { SubscriptionServer } from 'subscriptions-transport-ws'
import { formatApolloErrors } from 'apollo-server-errors'
import { execute, subscribe } from 'graphql'

// export patch
export function installSubscriptionHandlers(server) {
  // eslint-disable-next-line
  // @ts-ignore
  const that = this as any
  if (!that.subscriptionServerOptions) {
    if (that.config.gateway) {
      throw Error('Subscriptions are not supported when operating as a gateway')
    }
    if (that.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,
  } = that.subscriptionServerOptions
  const { schema } = that
  if (that.schema === undefined)
    throw new Error('Schema undefined during creation of subscription server.')
  that.subscriptionServer = SubscriptionServer.create(
    {
      schema,
      execute,
      subscribe,
      onConnect: onConnect || ((connectionParams) => ({ ...connectionParams })),
      onDisconnect,
      onOperation: async (message, connection) => {
        connection.formatResponse = (value) => ({
          ...value,
          errors:
            value.errors &&
            formatApolloErrors([...value.errors], {
              formatter: that.requestOptions.formatError,
              debug: that.requestOptions.debug,
            }),
        })
        connection.formatError = that.requestOptions.formatError
        let context = that.context ? that.context : { connection }
        try {
          context =
            typeof that.context === 'function'
              ? await that.context({ connection, payload: message.payload })
              : context
        } catch (e) {
          throw formatApolloErrors([e], {
            formatter: that.requestOptions.formatError,
            debug: that.requestOptions.debug,
          })[0]
        }
        return { ...connection, context }
      },
      keepAlive,
      validationRules: that.requestOptions.validationRules,
    },
    server instanceof ws.Server
      ? server
      : {
          server,
          path,
        }
  )
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment