Gathering detailed insights and metrics for aws-lambda-ws-link
Gathering detailed insights and metrics for aws-lambda-ws-link
Gathering detailed insights and metrics for aws-lambda-ws-link
Gathering detailed insights and metrics for aws-lambda-ws-link
aws-lambda-ws-link-apollo
aws-lambda-graphql-subscriptions-ws-link
graphql-lambda-client
An implementation of [`aws-lambda-graphql` Client][link-aws-lambda-graphql-client] without the extra bloat. It is used by [`lambda-graphql-ws-link`][link-graphql-lambda-ws-link] to integrate a [Serverless][link-serverless-plugin-graphql-lambda-ws] backend
Use AWS Lambda + AWS API Gateway v2 for GraphQL subscriptions over WebSocket and AWS API Gateway v1 for HTTP
npm install aws-lambda-ws-link
Typescript
Module System
Node Version
NPM Version
47.5
Supply Chain
63.6
Quality
74.1
Maintenance
100
Vulnerability
98.9
License
TypeScript (98.24%)
JavaScript (0.88%)
HTML (0.76%)
Shell (0.12%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
462 Stars
275 Commits
91 Forks
17 Watchers
20 Branches
17 Contributors
Updated on Mar 30, 2025
Latest Version
0.13.0
Package Id
aws-lambda-ws-link@0.13.0
Unpacked Size
5.59 kB
Size
2.66 kB
File Count
11
NPM Version
lerna/3.19.0/node@v12.13.0+x64 (darwin)
Node Version
12.13.0
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
3
5
⚠️ This documentation is currently for 1.0.0-alpha.X package which supports only subscriptions-transport-ws and drops the legacy protocol and client support! To use old version that supports legacy protocol and client see the link 0.13.0 below.
📖Documentation for aws-lambda-graphql0.13.0
Use Apollo Server Lambda with GraphQL subscriptions over WebSocket (AWS API Gateway v2).
With this library you can do:
In this quick example we're going to build a simple broadcasting server that broadcasts messages received using broadcastMessage
mutation to all subscribed connections.
Skip to final implementation if you don't need a step by step guide
First we need to install dependencies:
1yarn add aws-lambda-graphql graphql graphql-subscriptions aws-sdk 2# or 3npm install aws-lambda-graphql graphql graphql-subscriptions aws-sdk
Note that aws-sdk
is required only for local development, it's provided by the AWS Lambda by default when you deploy the app
Now we have all the dependencies installed so lets start with server implementation.
Our GraphQL server needs to know how to store connections and subscriptions because Lambdas are stateless. In order to do that we need create instances of the Connection manager and Subscription manager. We have two options of persistent storage for our connections and subscriptions.
DynamoDB:
1import { 2 DynamoDBConnectionManager, 3 DynamoDBSubscriptionManager, 4} from 'aws-lambda-graphql'; 5 6/* 7 By default subscriptions and connections use TTL of 2 hours. 8 This can be changed by `ttl` option in DynamoDBSubscriptionManager and DynamoDBConnectionManager. 9 10 ttl accepts a number in seconds (default is 7200 seconds) or 11 false to turn it off. 12 13 It's your responsibility to set up TTL on your connections and subscriptions tables. 14*/ 15const subscriptionManager = new DynamoDBSubscriptionManager(); 16const connectionManager = new DynamoDBConnectionManager({ 17 subscriptions: subscriptionManager, 18});
⚠️ in order to clean up stale connections and subscriptions please set up TTL on ttl
field in Connections, Subscriptions and SubscriptionOperations tables. You can turn off the TTL by setting up ttl
option to false
in DynamoDBSubscriptionManager
and DynamoDBConnectionManager
.
Redis:
1import { 2 RedisConnectionManager, 3 RedisSubscriptionManager, 4} from 'aws-lambda-graphql'; 5import Redis from 'ioredis'; 6 7const redisClient = new Redis({ 8 port: 6379, // Redis port 9 host: '127.0.0.1', // Redis host 10}); 11 12const subscriptionManager = new RedisSubscriptionManager({ 13 redisClient, 14}); 15const connectionManager = new RedisConnectionManager({ 16 subscriptionManager, 17 redisClient, 18});
In order to be able to broadcast messages (publish events) we need an Event store. Because our server can received a lot of messages we need to work with events in async, meaning that the actual events are not published directly from mutation but rather they are stored in underlying data store which works as an event source for our server. Because we decided to use DynamoDB as our persistent store, we are goint to use it as our event source.
1import { 2 DynamoDBConnectionManager, 3 DynamoDBEventStore, 4 DynamoDBSubscriptionManager, 5} from 'aws-lambda-graphql'; 6 7/* 8 By default event stores uses TTL of 2 hours on every event. 9 This can be changed by `ttl` option in DynamoDBEventStore. 10 ttl accepts a number in seconds (default is 7200 seconds) or 11 false to turn it off. 12 13 It's your responsibility to set up TTL on your events table. 14*/ 15const eventStore = new DynamoDBEventStore(); 16const subscriptionManager = new DynamoDBSubscriptionManager(); 17const connectionManager = new DynamoDBConnectionManager({ 18 subscriptionManager, 19});
That's it for now. Our eventStore
will use DynamoDB to store messages that we want to broadcast to all subscribed clients.
⚠️ in order to clean up old events, please set up TTL on ttl
field in Events store table. This can be turned off by setting up the ttl
option to false
.
Our server needs a GraphQL schema. So we'll create one.
1import { 2 DynamoDBConnectionManager, 3 DynamoDBEventStore, 4 DynamoDBSubscriptionManager, 5} from 'aws-lambda-graphql'; 6 7const eventStore = new DynamoDBEventStore(); 8const subscriptionManager = new DynamoDBSubscriptionManager(); 9const connectionManager = new DynamoDBConnectionManager({ 10 subscriptionManager, 11}); 12 13const typeDefs = /* GraphQL */ ` 14 type Mutation { 15 broadcastMessage(message: String!): String! 16 } 17 18 type Query { 19 """ 20 Dummy query so out server won't fail during instantiation 21 """ 22 dummy: String! 23 } 24 25 type Subscription { 26 messageBroadcast: String! 27 } 28`;
From given schema we already see that we need to somehow publish and process broadcasted message. For that purpose we must create a PubSub instance that uses our DynamoDB event store as underlying storage for events.
PubSub is responsible for publishing events and subscribing to events. Anyone can broadcast message using broadcastMessage
mutation (publish) and anyone connected over WebSocket can subscribed to messageBroadcast
subscription (subscribing) to receive broadcasted messages.
⚠️ Be careful! By default PubSub
serializes event payload to JSON. If you don't want this behaviour, set serializeEventPayload
option to false
on your PubSub
instance.
1import {
2 DynamoDBConnectionManager,
3 DynamoDBEventStore,
4 DynamoDBSubscriptionManager,
5 PubSub,
6} from 'aws-lambda-graphql';
7
8const eventStore = new DynamoDBEventStore();
9const subscriptionManager = new DynamoDBSubscriptionManager();
10const connectionManager = new DynamoDBConnectionManager({
11 subscriptionManager,
12});
13const pubSub = new PubSub({
14 eventStore,
15 // optional, if you don't want to store messages to your store as JSON
16 // serializeEventPayload: false,
17});
18
19const typeDefs = /* GraphQL */ `
20 type Mutation {
21 broadcastMessage(message: String!): String!
22 }
23
24 type Query {
25 """
26 Dummy query so out server won't fail during instantiation
27 """
28 dummy: String!
29 }
30
31 type Subscription {
32 messageBroadcast: String!
33 }
34`;
35
36const resolvers = {
37 Mutation: {
38 broadcastMessage: async (root, { message }) => {
39 await pubSub.publish('NEW_MESSAGE', { message });
40
41 return message;
42 },
43 },
44 Query: {
45 dummy: () => 'dummy',
46 },
47 Subscription: {
48 messageBroadcast: {
49 // rootValue is same as the event published above ({ message: string })
50 // but our subscription should return just a string, so we're going to use resolve
51 // to extract message from an event
52 resolve: (rootValue) => rootValue.message,
53 subscribe: pubSub.subscribe('NEW_MESSAGE'),
54 },
55 },
56};
Our GraphQL schema is now finished. Now we can instantiate the server so we can actually process HTTP and WebSocket events received by our Lambda server and send messages to subscribed clients.
In order to send messages to subscribed clients we need the last piece and it is a Event processor. Event processor is responsible for processing events published to our Event store and sending them to all connections that are subscribed for given event.
Because we use DynamoDB as an event store, we are going to use DynamoDBEventProcessor.
1import {
2 DynamoDBConnectionManager,
3 DynamoDBEventProcessor,
4 DynamoDBEventStore,
5 DynamoDBSubscriptionManager,
6 PubSub,
7 Server,
8} from 'aws-lambda-graphql';
9
10const eventStore = new DynamoDBEventStore();
11const eventProcessor = new DynamoDBEventProcessor();
12const subscriptionManager = new DynamoDBSubscriptionManager();
13const connectionManager = new DynamoDBConnectionManager({
14 subscriptions: subscriptionManager,
15});
16const pubSub = new PubSub({ eventStore });
17
18const typeDefs = /* GraphQL */ `
19 type Mutation {
20 broadcastMessage(message: String!): String!
21 }
22
23 type Query {
24 """
25 Dummy query so out server won't fail during instantiation
26 """
27 dummy: String!
28 }
29
30 type Subscription {
31 messageBroadcast: String!
32 }
33`;
34
35const resolvers = {
36 Mutation: {
37 broadcastMessage: async (root, { message }) => {
38 await pubSub.publish('NEW_MESSAGE', { message });
39
40 return message;
41 },
42 },
43 Query: {
44 dummy: () => 'dummy',
45 },
46 Subscription: {
47 messageBroadcast: {
48 // rootValue is same as the event published above ({ message: string })
49 // but our subscription should return just a string, so we're going to use resolve
50 // to extract message from an event
51 resolve: (rootValue) => rootValue.message,
52 subscribe: pubSub.subscribe('NEW_MESSAGE'),
53 },
54 },
55};
56
57const server = new Server({
58 // accepts all the apollo-server-lambda options and adds few extra options
59 // provided by this package
60 connectionManager,
61 eventProcessor,
62 resolvers,
63 subscriptionManager,
64 typeDefs,
65});
66
67export const handleWebSocket = server.createWebSocketHandler();
68export const handleHTTP = server.createHttpHandler();
69// this creates dynamodb event handler so we can send messages to subscribed clients
70export const handleEvents = server.createEventHandler();
Now our server is finished.
You need to map:
handleWebSocket
handlerhandleHTTP
handleEvents
.In order to do that you can use Serverless framework, see serverless.yml
file.
To connect to this server you can use Apollo Client + subscriptions-transport-ws
- see example in section 2
Sometime if you have complex schema you want to pass dependencies using context so it's easier to manage.
1import {
2 DynamoDBConnectionManager,
3 DynamoDBEventProcessor,
4 DynamoDBEventStore,
5 DynamoDBSubscriptionManager,
6 PubSub,
7 Server,
8} from 'aws-lambda-graphql';
9
10const eventStore = new DynamoDBEventStore();
11const eventProcessor = new DynamoDBEventProcessor();
12const subscriptionManager = new DynamoDBSubscriptionManager();
13const connectionManager = new DynamoDBConnectionManager({
14 subscriptions: subscriptionManager,
15});
16const pubSub = new PubSub({ eventStore });
17
18const typeDefs = /* GraphQL */ `
19 type Mutation {
20 broadcastMessage(message: String!): String!
21 }
22
23 type Query {
24 """
25 Dummy query so out server won't fail during instantiation
26 """
27 dummy: String!
28 }
29
30 type Subscription {
31 messageBroadcast: String!
32 }
33`;
34
35const resolvers = {
36 Mutation: {
37 broadcastMessage: async (root, { message }, ctx) => {
38 await ctx.pubSub.publish('NEW_MESSAGE', { message });
39
40 return message;
41 },
42 },
43 Query: {
44 dummy: () => 'dummy',
45 },
46 Subscription: {
47 messageBroadcast: {
48 resolve: (rootValue) => rootValue.message,
49 // subscribe works similarly as resolve in any other GraphQL type
50 // pubSub.subscribe() returns a resolver so we need to pass it all the args as were received
51 // so we can be sure that everything works correctly internally
52 subscribe: (rootValue, args, ctx, info) => {
53 return ctx.pubSub.subscribe('NEW_MESSAGE')(rootValue, args, ctx, info);
54 },
55 },
56 },
57};
58
59const server = new Server({
60 // accepts all the apollo-server-lambda options and adds few extra options
61 // provided by this package
62 context: {
63 pubSub,
64 },
65 connectionManager,
66 eventProcessor,
67 resolvers,
68 subscriptionManager,
69 typeDefs,
70});
71
72export const handleWebSocket = server.createWebSocketHandler();
73export const handleHTTP = server.createHttpHandler();
74// this creates dynamodb event handler so we can send messages to subscribed clients
75export const handleEvents = server.createEventHandler();
subscriptions-transport-ws
First install dependencies
1yarn add @apollo/client @apollo/link-ws subscriptions-transport-ws 2# or 3npm install @apollo/client @apollo/link-ws subscriptions-transport-ws
1import { WebSocketLink } from '@apollo/link-ws';
2import { SubscriptionClient } from 'subscriptions-transport-ws';
3import { ApolloProvider, ApolloClient, InMemoryCache } from '@apollo/client';
4
5const wsClient = new SubscriptionClient(
6 'ws://localhost:8000', // please provide the uri of the api gateway v2 endpoint
7 { lazy: true, reconnect: true },
8 null,
9 [],
10);
11const link = new WebSocketLink(wsClient);
12const client = new ApolloClient({
13 cache: new InMemoryCache(),
14 link,
15});
To deploy your api created using this library please see serverless.yml
template of example app.
This library supports serverless-offline. But you have to do small changes in your code to actually support it, it's not automatical.
You need to set up custom endpoint for ApiGatewayManagementApi and custom endpoint for DynamoDB if you're using it. Please refer to chat-example-server
source code.
GraphQL client and server implementation for AWS Lambda.
See package
Current infrastructure is implemented using AWS Lambda + AWS API Gateway v2 + AWS DynamoDB (with DynamoDB streams). But it can be implemented using various solutions (Kinesis, etc) because it's written to be modular.
serverless.yml
file for easy deploymentyarn.lock
is commited.Unreleased
section in your PR.1yarn test 2# running tests in watch mode 3yarn test:watch
1yarn build
Running tests locally:
1yarn test
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
MIT
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
Found 9/25 approved changesets -- score normalized to 3
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
167 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More