Skip to content

Commit 786c58e

Browse files
refactor to use one Server implementation with Apollo Server Lambda as base implementation
1 parent f09d31d commit 786c58e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2593
-2519
lines changed

Diff for: CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
134134

135135
### [v0.1.0](https://github.com/michalkvasnicak/aws-lambda-graphql/releases/tag/v0.1.0) - 2019-01-13
136136

137-
## `aws-lambda-ws-link`
137+
## `aws-lambda-ws-link` **⚠️ Deprecated, do not use with versions newer that `0.13.0`**
138138

139139
### [Unreleased](https://github.com/michalkvasnicak/aws-lambda-graphql/compare/[email protected])
140140

Diff for: README.md

+196-132
Large diffs are not rendered by default.

Diff for: package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
"private": true,
33
"dependencies": {
44
"@types/graphql": "^14.5.0",
5-
"apollo-link": "^1.2.13",
65
"aws-sdk": "^2.577.0",
76
"graphql": "^14.5.8",
87
"graphql-subscriptions": "^1.1.0"
98
},
109
"resolutions": {
10+
"@types/aws-lambda": "^8.10.36",
1111
"@types/node": "10.17.5"
1212
},
1313
"devDependencies": {
@@ -19,6 +19,7 @@
1919
"@babel/preset-typescript": "^7.7.2",
2020
"@types/jest": "^24.0.23",
2121
"@types/node": "10.17.5",
22+
"@types/node-fetch": "^2.5.4",
2223
"@typescript-eslint/eslint-plugin": "^2.8.0",
2324
"@typescript-eslint/parser": "^2.8.0",
2425
"eslint": "^6.6.0",

Diff for: packages/aws-lambda-graphql/README.md

+32-33
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
[![CircleCI](https://img.shields.io/circleci/project/github/michalkvasnicak/aws-lambda-graphql/master.svg?style=flat-square)](https://circleci.com/gh/michalkvasnicak/aws-lambda-graphql)
44
[![aws-lambda-graphql package version](https://img.shields.io/npm/v/aws-lambda-graphql?color=green&label=aws-lambda-graphql&style=flat-square)](https://www.npmjs.com/package/aws-lambda-graphql)
55

6-
GraphQL server and client implementation for AWS Lambda with WebSocket (AWS API Gateway v2) and HTTP support (AWS API Gateway v1).
6+
Use [Apollo Server Lambda](https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-lambda) with GraphQL subscriptions over WebSocket (AWS API Gateway v2).
77

8-
The server is fully compatible with Apollo's [`subscriptions-transport-ws`](https://github.com/apollographql/subscriptions-transport-ws).
8+
With this library you can do:
9+
10+
- same things as with [apollo-server-lambda](https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-lambda) by utiizing AWS API Gateway v1
11+
- GraphQL subscriptions over WebSocket by utilizing AWS API Gateway v2 and [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws)
912

1013
## Table of contents
1114

@@ -17,60 +20,56 @@ The server is fully compatible with Apollo's [`subscriptions-transport-ws`](http
1720
## Installation
1821

1922
```console
20-
yarn add aws-lambda-graphql apollo-link graphql graphql-subscriptions
23+
yarn add aws-lambda-graphql graphql graphql-subscriptions
2124
# or
22-
npm install aws-lamda-graphql apollo-link graphql graphql-subscriptions
25+
npm install aws-lamda-graphql graphql graphql-subscriptions
2326
```
2427

2528
## Usage
2629

27-
To implement WebSocket event handler and event stream handler please see the [example](https://github.com/michalkvasnicak/aws-lambda-graphql#1-websocket-server-handler).
28-
29-
To implement HTTP event handler please see the [example](https://github.com/michalkvasnicak/aws-lambda-graphql#11-http-server-handler).
30+
There is a [quick start guide](https://github.com/michalkvasnicak/aws-lambda-graphql#quick-start).
3031

3132
## API
3233

33-
### `createDynamoDBEventProcessor(options: Options): event handler function`
34+
### `Server`
3435

35-
Creates an AWS DynamoDB Stream handler.
36+
Creates an [Apollo Lambda server](https://www.npmjs.com/package/apollo-server-lambda).
3637

3738
#### Options
3839

40+
All options from Apollo Lambda Server and
41+
3942
- **connectionManager** (`IConnectionManager`, `required`)
40-
- **context** (`object` or [`Context creator function`](#context-creator-function), `optional`)
41-
- **schema** (`GraphQLSchema`, `required`)
43+
- **eventProcessor** (`IEventProcessor`, `required`)
4244
- **subscriptionManager** (`ISubscriptionManager`, `required`)
45+
- **subscriptions** (`optional`)
46+
- **`onConnect(messagePayload: object, connection: IConnection): Promise<boolean|object> | object | boolean`** (`optional`)
47+
- **`onOperation(message: OperationRequest, params: ExecutionParams, connection: IConnection): Promise<ExecutionParams>|ExecutionParams`** (`optional`)
48+
- **`onOperationComplete(connection: IConnection, operationId: string): void`** (`optional`)
49+
- **`onDisconnect(connection: IConnection): void`** (`optional`)
50+
- **waitForInitialization** (`optional`) - if connection is not initialised on GraphQL operation, wait for connection to be initialised or throw prohibited connection error. If `onConnect` is specified then we wait for initialisation otherwise we don't wait. (this is usefull if you're performing authentication in `onConnect`).
51+
- **retryCount** (`number`, `optional`, `default 10`) - how many times should we try to check the connection state?
52+
- **timeout** (`number`, `optional`, `default 50ms`) - how long should we wait (in milliseconds) until we try to check the connection state again?
4353

44-
### `createHttpHandler(options: Options): API Gateway v1 HTTP event handler function`
54+
#### `createHttpHandler()`
4555

46-
Creates an AWS API Gateway v1 event handler.
56+
Creates an AWS Lambda API Gateway v1 handler. Events are handled by [apollo-server-lambda](https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-lambda)
4757

48-
#### Options
58+
#### `createWebSocketHandler()`
4959

50-
- **connectionManager** (`IConnectionManager`, `required`)
51-
- **context** (`object` or [`Context creator function`](#context-creator-function), `optional`)
52-
- **schema** (`GraphQLSchema`, `required`)
53-
- **formatResponse** (`(body: any) => string`, `optional`) - formats response for `body` property of an AWS ApiGateway v1 response. Default is `JSON.stringify`
54-
- **validationRules** (`array of GraphQL validation rules`, `optional`)
60+
Creates an AWS Lambda API Gateway v2 handler that supports GraphQL subscriptions over WebSocket.
5561

56-
### `createWsHandler(options: Options): API Gateway v2 WebSocket event handler function`
62+
#### `createEventHandler()`
5763

58-
Creates an AWS API Gateway v1 event handler.
64+
Creates an AWS Lambda handler for events from events source (for example DynamoDBEventStore). This method internally work with `IEventProcessor`.
65+
66+
### `DynamoDBEventProcessor: IEventProcessor`
67+
68+
AWS Lambda DynamoDB stream handler. DynamoDBEventProcessor is used internally by Server.
5969

6070
#### Options
6171

62-
- **connectionManager** (`IConnectionManager`, `required`)
63-
- **context** (`object` or [`Context creator function`](#context-creator-function), `optional`)
64-
- **schema** (`GraphQLSchema`, `required`)
65-
- **subscriptionManager** (`ISubscriptionManager`, `required`)
66-
- **`onConnect(messagePayload: object, connection: IConnection): Promise<boolean|object> | object | boolean`**
67-
- **`onOperation(message: OperationRequest, params: object, connection: IConnection): Promise<object>|object`** (`optional`)
68-
- **`onOperationComplete(connection: IConnection, operationId: string): void`** (`optional`)
69-
- **`onDisconnect(connection: IConnection): void`** (`optional`)
70-
- **validationRules** (`array of GraphQL validation rules`, `optional`)
71-
- **waitForInitialization** (`optional`) - if connection is not initialised on GraphQL operation, wait for connection to be initialised or throw prohibited connection error. If `onConnect` is specified then we wait for initialisation otherwise we don't wait. (this is usefull if you're performing authentication in `onConnect`).
72-
- **retryCount** (`number`, `optional`, `default 10`) - how many times should we try to check the connection state?
73-
- **timeout** (`number`, `optional`, `default 50ms`) - how long should we wait (in milliseconds) until we try to check the connection state again?
72+
- **onError** (`(err: any) => void`, `optional`)
7473

7574
### `DynamoDBConnectionManager: IConnectionManager`
7675

Diff for: packages/aws-lambda-graphql/package.json

+9-13
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
},
1313
"sideEffects": false,
1414
"keywords": [
15+
"apollo",
1516
"aws",
1617
"lambda",
1718
"apollo",
@@ -20,38 +21,33 @@
2021
"apigateway",
2122
"websocket",
2223
"http",
23-
"graphql-subscriptions"
24+
"graphql-subscriptions",
25+
"serverless"
2426
],
2527
"files": [
2628
"dist",
2729
"README.md",
2830
"LICENSE"
2931
],
30-
"description": "GraphQL server and client implementation for AWS Lambda with WebSocket support (API Gateway v1 + v2)",
32+
"description": "Apollo server for AWS Lambda with WebSocket subscriptions support over API Gateway v1 + v2)",
3133
"dependencies": {
3234
"@types/aws-lambda": "^8.10.36",
33-
"@types/backo2": "^1.0.1",
34-
"@types/websocket": "^1.0.0",
35-
"backo2": "1.0.2",
36-
"content-type": "^1.0.4",
37-
"eventemitter3": "^3.1.2",
35+
"apollo-server-core": "^2.9.14",
36+
"apollo-server-lambda": "^2.9.14",
3837
"iterall": "^1.2.2",
39-
"ulid": "^2.3.0",
40-
"xstate": "^4.2.3"
38+
"ulid": "^2.3.0"
4139
},
4240
"peerDependencies": {
43-
"apollo-link": "^1.2.6",
4441
"aws-sdk": "^2.387.0",
4542
"graphql": "^14.0.2",
4643
"graphql-subscriptions": "^1.0.0"
4744
},
4845
"engines": {
49-
"node": ">=8"
46+
"node": ">=10"
5047
},
5148
"engineStrict": true,
5249
"devDependencies": {
53-
"@types/content-type": "^1.1.2",
54-
"apollo-link": "1.2.11",
50+
"apollo-link": "^1.2.11",
5551
"graphql-tag": "^2.10.1",
5652
"graphql-tools": "^4.0.6",
5753
"mock-socket": "^8.0.5",

Diff for: packages/aws-lambda-graphql/src/ArrayPubSub.ts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { createAsyncIterator } from 'iterall';
2+
import { ISubscriptionEvent } from './types';
3+
4+
/**
5+
* Array PubSub works as local PubSub that is already fed with all the events that were published
6+
*
7+
* Each time you call asyncIterator it will create an iterator that iterates over events
8+
*/
9+
export class ArrayPubSub {
10+
private events: ISubscriptionEvent[];
11+
12+
constructor(events: ISubscriptionEvent[]) {
13+
this.events = events;
14+
}
15+
16+
async publish() {
17+
throw new Error('ArrayPubSub is read only');
18+
}
19+
20+
async subscribe(): Promise<number> {
21+
throw new Error('Please do not use this PubSub implementation');
22+
}
23+
24+
async unsubscribe() {
25+
throw new Error('Please do not use this PubSub implementation');
26+
}
27+
28+
asyncIterator(eventNames: string | string[]) {
29+
const names = Array.isArray(eventNames) ? eventNames : [eventNames];
30+
31+
return createAsyncIterator(
32+
this.events
33+
.filter(event => names.includes(event.event))
34+
.map(event =>
35+
typeof event.payload === 'string'
36+
? JSON.parse(event.payload)
37+
: event.payload,
38+
),
39+
);
40+
}
41+
}

Diff for: packages/aws-lambda-graphql/src/DynamoDBConnectionManager.ts

+7-31
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ type Options = {
1515
subscriptions: ISubscriptionManager;
1616
};
1717

18-
class DynamoDBConnectionManager implements IConnectionManager {
18+
/**
19+
* DynamoDBConnectionManager
20+
*
21+
* Stores connections in DynamoDB table (default table name is Connections, you can override that)
22+
*/
23+
export class DynamoDBConnectionManager implements IConnectionManager {
1924
private connectionsTable: string;
2025

2126
private db: DynamoDB.DocumentClient;
@@ -28,10 +33,7 @@ class DynamoDBConnectionManager implements IConnectionManager {
2833
this.subscriptions = subscriptions;
2934
}
3035

31-
hydrateConnection = async (
32-
connectionId: string,
33-
useLegacyProtocol?: boolean,
34-
): Promise<IConnection> => {
36+
hydrateConnection = async (connectionId: string): Promise<IConnection> => {
3537
// if connection is not found, throw so we can terminate connection
3638
const result = await this.db
3739
.get({
@@ -46,11 +48,6 @@ class DynamoDBConnectionManager implements IConnectionManager {
4648
throw new ConnectionNotFoundError(`Connection ${connectionId} not found`);
4749
}
4850

49-
if (useLegacyProtocol && !result.Item.data.useLegacyProtocol) {
50-
await this.setLegacyProtocol(result.Item as IConnection);
51-
result.Item.data.useLegacyProtocol = true;
52-
}
53-
5451
return result.Item as IConnection;
5552
};
5653

@@ -75,24 +72,6 @@ class DynamoDBConnectionManager implements IConnectionManager {
7572
.promise();
7673
};
7774

78-
setLegacyProtocol = async (connection: IConnection): Promise<void> => {
79-
await this.db
80-
.update({
81-
TableName: this.connectionsTable,
82-
Key: {
83-
id: connection.id,
84-
},
85-
UpdateExpression: 'set #data.useLegacyProtocol = :useLegacyProtocol',
86-
ExpressionAttributeValues: {
87-
':useLegacyProtocol': true,
88-
},
89-
ExpressionAttributeNames: {
90-
'#data': 'data',
91-
},
92-
})
93-
.promise();
94-
};
95-
9675
registerConnection = async ({
9776
connectionId,
9877
endpoint,
@@ -170,6 +149,3 @@ class DynamoDBConnectionManager implements IConnectionManager {
170149
await managementApi.deleteConnection({ ConnectionId: id }).promise();
171150
};
172151
}
173-
174-
export { DynamoDBConnectionManager };
175-
export default DynamoDBConnectionManager;

0 commit comments

Comments
 (0)