diff --git a/CHANGELOG.md b/CHANGELOG.md index e2665e301..6f9cdb117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ### vNEXT +- pass `request` (`upgradeReq`) to `ConnectionContext` [PR #369](https://github.com/apollographql/subscriptions-transport-ws/pull/369) +- pass `ConnectionContext` to `onDisconnect()` as second argument [PR #369](https://github.com/apollographql/subscriptions-transport-ws/pull/369) ### 0.9.6 - fix shallow cloning on contexts which are classes diff --git a/README.md b/README.md index 5f8030742..d277ff9a1 100644 --- a/README.md +++ b/README.md @@ -302,8 +302,8 @@ ReactDOM.render( * `subscribe?: (schema, document, rootValue, contextValue, variableValues, operationName) => Promise>` : GraphQL `subscribe` function, provide the default one from `graphql` package. * `onOperation?: (message: SubscribeMessage, params: SubscriptionOptions, webSocket: WebSocket)` : optional method to create custom params that will be used when resolving this operation * `onOperationComplete?: (webSocket: WebSocket, opId: string)` : optional method that called when a GraphQL operation is done (for query and mutation it's immeditaly, and for subscriptions when unsubscribing) - * `onConnect?: (connectionParams: Object, webSocket: WebSocket)` : optional method that called when a client connects to the socket, called with the `connectionParams` from the client, if the return value is an object, its elements will be added to the context. return `false` or throw an exception to reject the connection. May return a Promise. - * `onDisconnect?: (webSocket: WebSocket)` : optional method that called when a client disconnects + * `onConnect?: (connectionParams: Object, webSocket: WebSocket, context: ConnectionContext)` : optional method that called when a client connects to the socket, called with the `connectionParams` from the client, if the return value is an object, its elements will be added to the context. return `false` or throw an exception to reject the connection. May return a Promise. + * `onDisconnect?: (webSocket: WebSocket, context: ConnectionContext)` : optional method that called when a client disconnects * `keepAlive?: number` : optional interval in ms to send `KEEPALIVE` messages to all clients - `socketOptions: {WebSocket.IServerOptions}` : options to pass to the WebSocket object (full docs [here](https://github.com/websockets/ws/blob/master/doc/ws.md)) diff --git a/docs/source/lifecycle-events.md b/docs/source/lifecycle-events.md index a005b9090..01e1c960e 100644 --- a/docs/source/lifecycle-events.md +++ b/docs/source/lifecycle-events.md @@ -13,21 +13,21 @@ title: Lifecycle Events const subscriptionsServer = new SubscriptionServer( { subscriptionManager: subscriptionManager, - onConnect: (connectionParams, webSocket) => { - // ... + onConnect: (connectionParams, webSocket, context) => { + // ... }, onOperation: (message, params, webSocket) => { - // ... + // ... }, - onOperationDone: (webSocket) => { - // ... + onOperationDone: webSocket => { + // ... + }, + onDisconnect: (webSocket, context) => { + // ... }, - onDisconnect: (webSocket) => { - // ... - } }, { - server: websocketServer - } + server: websocketServer, + }, ); ``` diff --git a/src/server.ts b/src/server.ts index 3d14b3216..c2cf01033 100644 --- a/src/server.ts +++ b/src/server.ts @@ -35,6 +35,7 @@ export type ConnectionContext = { initPromise?: Promise, isLegacy: boolean, socket: WebSocket, + request: IncomingMessage, operations: { [opId: string]: ExecutionIterator, }, @@ -143,6 +144,7 @@ export class SubscriptionServer { connectionContext.initPromise = Promise.resolve(true); connectionContext.isLegacy = false; connectionContext.socket = socket; + connectionContext.request = request; connectionContext.operations = {}; const connectionClosedHandler = (error: any) => { @@ -162,7 +164,7 @@ export class SubscriptionServer { this.onClose(connectionContext); if (this.onDisconnect) { - this.onDisconnect(socket); + this.onDisconnect(socket, connectionContext); } }; @@ -466,3 +468,4 @@ export class SubscriptionServer { ); } } + diff --git a/src/test/tests.ts b/src/test/tests.ts index 3f1e8c5bd..345b9ad68 100644 --- a/src/test/tests.ts +++ b/src/test/tests.ts @@ -1450,6 +1450,16 @@ describe('Server', function () { }, 200); }); + it('should trigger onConnect with the request available in ConnectionContext', (done) => { + new SubscriptionClient(`ws://localhost:${EVENTS_TEST_PORT}/`); + + setTimeout(() => { + assert(eventsOptions.onConnect.calledOnce); + expect(eventsOptions.onConnect.getCall(0).args[2].request).to.be.an.instanceof(IncomingMessage); + done(); + }, 200); + }); + it('should trigger onConnect and return GQL_CONNECTION_ERROR with error', (done) => { const connectionCallbackSpy = sinon.spy(); @@ -1507,6 +1517,18 @@ describe('Server', function () { }, 200); }); + it('should trigger onDisconnect with ConnectionContext as second argument', (done) => { + const client = new SubscriptionClient(`ws://localhost:${EVENTS_TEST_PORT}/`); + setTimeout(() => { + client.client.close(); + }, 100); + setTimeout(() => { + assert(eventsOptions.onDisconnect.calledOnce); + expect(eventsOptions.onConnect.getCall(0).args[1]).to.not.be.undefined; + done(); + }, 200); + }); + it('should call unsubscribe when client closes the connection', (done) => { const client = new SubscriptionClient(`ws://localhost:${EVENTS_TEST_PORT}/`); const spy = sinon.spy(eventsServer as any, 'unsubscribe');