diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a284b35e79..8503b9ffd26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ The version headers in this history reflect the versions of Apollo Server itself > The changes noted within this `vNEXT` section have not been released yet. New PRs and commits which introduce changes should include an entry in this `vNEXT` section as part of their development. With few exceptions, the format of the entry should follow convention (i.e., prefix with package name, use markdown `backtick formatting` for package names and code, suffix with a link to the change-set à la `[PR #YYY](https://link/pull/YYY)`, etc.). When a release is being prepared, a new header will be (manually) created below and the appropriate changes within that release will be moved into the new section. -- _Nothing yet! Stay tuned!_ +- subscriptions: Fix bug which prevented `installSubscriptionHandlers` from accepting a `websocket.Server` (as intended in [PR #1966](https://github.com/apollographql/apollo-server/pull/1966)) and also added support for other `http.Server` variations (e.g., Tls). [Issue #4198](https://github.com/apollographql/apollo-server/issues/4198) [PR #4200](https://github.com/apollographql/apollo-server/pull/4200) ## v2.16.1 diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index bdd93df6908..c903c9722ee 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -3,7 +3,11 @@ import { addMockFunctionsToSchema, GraphQLParseOptions, } from 'graphql-tools'; +import { Server as NetServer } from 'net' +import { Server as TlsServer } from 'tls' import { Server as HttpServer } from 'http'; +import { Http2Server, Http2SecureServer } from 'http2'; +import { Server as HttpsServer } from 'https'; import loglevel from 'loglevel'; import { execute, @@ -602,7 +606,7 @@ export class ApolloServerBase { } } - public installSubscriptionHandlers(server: HttpServer | WebSocket.Server) { + public installSubscriptionHandlers(server: HttpServer | HttpsServer | Http2Server | Http2SecureServer | WebSocket.Server) { if (!this.subscriptionServerOptions) { if (this.config.gateway) { throw Error( @@ -678,12 +682,12 @@ export class ApolloServerBase { keepAlive, validationRules: this.requestOptions.validationRules }, - server instanceof WebSocket.Server - ? server - : { - server, - path, - }, + server instanceof NetServer || server instanceof TlsServer + ? { + server, + path, + } + : server ); } diff --git a/packages/apollo-server-integration-testsuite/src/ApolloServer.ts b/packages/apollo-server-integration-testsuite/src/ApolloServer.ts index bfcb8cfa4ff..bcc0caf3996 100644 --- a/packages/apollo-server-integration-testsuite/src/ApolloServer.ts +++ b/packages/apollo-server-integration-testsuite/src/ApolloServer.ts @@ -2041,6 +2041,87 @@ export function testApolloServer( }) .catch(done.fail); }); + + it('takes websocket server subscriptions configuration', done => { + const onConnect = jest.fn(connectionParams => ({ + ...connectionParams, + })); + const typeDefs = gql` + type Query { + hi: String + } + + type Subscription { + num: Int + } + `; + + const query = ` + subscription { + num + } + `; + + const resolvers = { + Query: { + hi: () => 'here to placate graphql-js', + }, + Subscription: { + num: { + subscribe: () => { + createEvent(1); + createEvent(2); + createEvent(3); + return pubsub.asyncIterator(SOMETHING_CHANGED_TOPIC); + }, + }, + }, + }; + + const path = '/sub'; + createApolloServer({ + typeDefs, + resolvers, + subscriptions: { onConnect, path }, + }) + .then(({ port, server }) => { + const subPort = (typeof port === "number" ? port : parseInt(port)) + 1 + const websocketServer = new WebSocket.Server({port: subPort}) + server.installSubscriptionHandlers(websocketServer); + expect(onConnect).not.toBeCalled(); + + expect(server.subscriptionsPath).toEqual(path); + const client = new SubscriptionClient( + `ws://localhost:${subPort}${server.subscriptionsPath}`, + {}, + WebSocket, + ); + + const observable = client.request({ query }); + + let i = 1; + subscription = observable.subscribe({ + next: ({ data }) => { + try { + expect(onConnect).toHaveBeenCalledTimes(1); + expect(data.num).toEqual(i); + if (i === 3) { + done(); + } + i++; + } catch (e) { + done.fail(e); + } + }, + error: done.fail, + complete: () => { + done.fail(new Error('should not complete')); + }, + }); + }) + .catch(done.fail); + }); + it('allows introspection when introspection is enabled on ApolloServer', done => { const typeDefs = gql` type Query {