Skip to content

Commit 06d074f

Browse files
jcane86michalkvasnicak
authored andcommitted
add onWebsocketConnect handler
1 parent 4987022 commit 06d074f

File tree

2 files changed

+74
-3
lines changed

2 files changed

+74
-3
lines changed

packages/aws-lambda-graphql/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ All options from Apollo Lambda Server and
4848
- **onError** (`(err: any) => void`, `optional`) - use to log errors from websocket handler on unknown error
4949
- **subscriptionManager** (`ISubscriptionManager`, `required`)
5050
- **subscriptions** (`optional`)
51-
- **`onConnect(messagePayload: object, connection: IConnection, event: APIGatewayWebSocketEvent, context: LambdaContext): Promise<boolean|object> | object | boolean`** (`optional`) - Return an object to set a context to your connection object saved in the database e.g. for saving authentication details
51+
- **`onWebsocketConnect(connection: IConnection, event: APIGatewayWebSocketEvent, context: LambdaContext): Promise<boolean|object> | object | boolean`** (`optional`) - onWebsocketConnect is called when the Websocket connection is initialized ($connect route). Return an object to set a context to your connection object saved in the database e.g. for saving authentication details. This is especially useful to get authentication details (API GW authorizers only run in $connect route)
52+
- **`onConnect(messagePayload: object, connection: IConnection, event: APIGatewayWebSocketEvent, context: LambdaContext): Promise<boolean|object> | object | boolean`** (`optional`) - onConnect is called when the GraphQL connection is initialized (connection_init message). Return an object to set a context to your connection object saved in the database e.g. for saving authentication details. NOTE: This is not the websocket $connect route, see onWebsocketConnect for the $connect route.
5253
- **`onOperation(message: OperationRequest, params: ExecutionParams, connection: IConnection): Promise<ExecutionParams>|ExecutionParams`** (`optional`)
5354
- **`onOperationComplete(connection: IConnection, operationId: string): void`** (`optional`)
5455
- **`onDisconnect(connection: IConnection): void`** (`optional`)

packages/aws-lambda-graphql/src/Server.ts

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,27 @@ export interface ServerConfig<
6767
connection: IConnection,
6868
operationId: string,
6969
) => void;
70+
/**
71+
* onWebsocketConnect is called when the Websocket connection is initialized ($connect route).
72+
* Return an object to set a context to your connection object saved in the database e.g. for saving authentication details.
73+
* This is especially useful to get authentication details (API GW authorizers only run in $connect route)
74+
*
75+
*/
76+
onWebsocketConnect?: (
77+
connection: IConnection,
78+
event: APIGatewayWebSocketEvent,
79+
context: LambdaContext,
80+
) =>
81+
| Promise<boolean | { [key: string]: any }>
82+
| boolean
83+
| { [key: string]: any };
84+
/**
85+
* onConnect is called when the GraphQL connection is initialized (connection_init message).
86+
* Return an object to set a context to your connection object saved in the database e.g. for saving authentication details.
87+
*
88+
* NOTE: This is not the websocket $connect route, see onWebsocketConnect for the $connect route
89+
*
90+
*/
7091
onConnect?: (
7192
messagePayload: { [key: string]: any } | undefined | null,
7293
connection: IConnection,
@@ -227,16 +248,65 @@ export class Server<
227248
// based on routeKey, do actions
228249
switch (event.requestContext.routeKey) {
229250
case '$connect': {
251+
const {
252+
onWebsocketConnect,
253+
} = this.subscriptionOptions || {};
254+
230255
// register connection
231256
// if error is thrown during registration, connection is rejected
232257
// we can implement some sort of authorization here
233258
const endpoint = extractEndpointFromEvent(event);
234259

235-
await this.connectionManager.registerConnection({
260+
const connection = await this.connectionManager.registerConnection({
236261
endpoint,
237262
connectionId: event.requestContext.connectionId,
238263
});
239264

265+
let newConnectionContext = {}
266+
267+
if (onWebsocketConnect) {
268+
try {
269+
const result = await onWebsocketConnect(
270+
connection,
271+
event,
272+
lambdaContext,
273+
);
274+
275+
if (result === false) {
276+
throw new Error('Prohibited connection!');
277+
} else if (result !== null && typeof result === 'object') {
278+
newConnectionContext = result
279+
}
280+
} catch (err) {
281+
const errorResponse = formatMessage({
282+
type: SERVER_EVENT_TYPES.GQL_ERROR,
283+
payload: { message: err.message },
284+
});
285+
286+
await this.connectionManager.sendToConnection(
287+
connection,
288+
errorResponse,
289+
);
290+
await this.connectionManager.closeConnection(connection);
291+
292+
return {
293+
body: errorResponse,
294+
statusCode: 401,
295+
};
296+
}
297+
}
298+
299+
// set connection context which will be available during graphql execution
300+
const connectionData = {
301+
...connection.data,
302+
context: newConnectionContext
303+
};
304+
305+
await this.connectionManager.setConnectionData(
306+
connectionData,
307+
connection,
308+
);
309+
240310
return {
241311
body: '',
242312
headers: event.headers?.['Sec-WebSocket-Protocol']?.includes(
@@ -336,7 +406,7 @@ export class Server<
336406
// set connection context which will be available during graphql execution
337407
const connectionData = {
338408
...connection.data,
339-
context: newConnectionContext,
409+
context: {...connection.data.context, ...newConnectionContext},
340410
isInitialized: true,
341411
};
342412

0 commit comments

Comments
 (0)