As of version 0.8.0 you can use subscriptions-transport-ws client.
This library uses typescript so for now use types as documentation
This library uses yarn and yarn workspaces so only yarn.lock
is commited.
This library is created because I wanted to try if it's possible to implement GraphQL server with subscriptions in AWS Lambda. And yes it is possible with AWS API Gateway v2.
- Infrastructure
- Usage (server)
- Usage (Apollo client + subscriptions-transport-ws)
- Usage (Apollo client + aws-lambda-ws-link)
- Examples
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.
npm install aws-lamda-graphql apollo-link graphql graphql-subscriptions
# or
yarn add aws-lambda-graphql apollo-link graphql graphql-subscriptions
const {
createDynamoDBEventProcessor,
createWsHandler,
DynamoDBConnectionManager,
DynamoDBEventStore,
DynamoDBSubscriptionManager,
PubSub,
} = require('aws-lambda-graphql');
import { makeExecutableSchema } from 'graphql-tools';
// this only processes AWS Api Gateway v2 events
// if you want to process HTTP too, use createHttpHandler
// or you can use both, see chat-example-server
// instantiate event store
// by default uses Events table (can be changed)
const eventStore = new DynamoDBEventStore();
const pubSub = new PubSub({ eventStore });
const subscriptionManager = new DynamoDBSubscriptionManager();
const connectionManager = new DynamoDBConnectionManager({
subscriptions: subscriptionManager,
});
const schema = makeExecutableSchema({
typeDefs: /* GraphQL */ `
type Mutation {
publish(message: String!): String!
}
type Query {
dummy: String!
}
type Subscription {
messageFeed: String!
}
`,
resolvers: {
Query: {
dummy: () => 'dummy',
},
Mutation: {
publish: async (rootValue, { message }) => {
await pubSub.publish('NEW_MESSAGE)', { message });
return message;
},
},
Subscription: {
messageFeed: {
// rootValue is same as object published using pubSub.publish
resolve: rootValue => rootValue.message,
subscribe: pubSub.subscribe('NEW_MESSAGE'),
},
},
},
});
const eventProcessor = createDynamoDBEventProcessor({
connectionManager,
schema,
subscriptionManager,
});
const wsHandler = createWsHandler({
connectionManager,
schema,
subscriptionManager,
// validationRules
/* Lifecycle methods available from 0.9.0 */
/* allows to provide custom parameters for operation execution */
// onOperation?: (message: OperationRequest, params: { query, variables, operationName, context, schema }, connection: IConnection) => Promise<Object> | Object,
/* executes on subscription stop operations, receives connection object and operation ID as arguments */
// onOperationComplete?: (connection: IConnection, opId: string) => void,
/*
executes on GQL_CONNECTION_INIT message, receives payload of said message and allows to reject connection when onConnect thorws error or returns false,
write method return value to connection context which will be available during graphql resolver execution.
If onConnect is not defined or returns true, we put everything in GQL_CONNECTION_INIT messagePayload to connection context.
*/
// onConnect?: (messagePayload: { [key: string]: any }, connection: IConnection) => Promise<boolean | { [key: string]: any }> | boolean | { [key: string]: any },
/* executes on $disconnect, receives connection object as argument */
// onDisconnect?: (connection: IConnection) => void,
// waitForInitialization (available from 0.11.0)
// waitForInitialization: { retryCount?: number, timeout?: number },
});
// use these handlers from your lambda and map them to
// api gateway v2 and DynamoDB events table
module.exports.consumeWsEvent = wsHandler;
module.exports.consumeDynamoDBStream = eventProcessor;
This library can be used with Apollo client without any problems thanks to AlpacaGoesCrazy's pull request #27.
yarn add apollo-client subscriptions-transport-ws
# or
npm install apollo-client subscriptions-transport-ws
import { WebSocketLink } from 'apollo-link-ws';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloClient } from 'apollo-client';
import { SubscriptionClient } from 'subscriptions-transport-ws';
const wsClient = new SubscriptionClient(
'ws://localhost:8000',
{ lazy: true, reconnect: true },
null,
[],
);
const link = new WebSocketLink(wsClient);
const client = new ApolloClient({
cache: new InMemoryCache(),
link,
});
// ...
This library also have it's own client which is using a little bit different protocol than Apollo's.
yarn add aws-lambda-ws-link graphql
# or
npm install aws-lambda-ws-link graphql
import { Client, WebSocketLink } from 'aws-lambda-ws-link';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloClient } from 'apollo-client';
const wsClient = new Client({
uri: 'ws://localhost:8000',
});
const link = new WebSocketLink(wsClient);
const client = new ApolloClient({
cache: new InMemoryCache(),
link,
});
// ...
- Chat App - React app
- Chat Server
- contains AWS Lambda that handles HTTP, WebSocket and DynamoDB streams
- also includes serverless.yaml file for easy deployment
Running tests locally:
yarn install
yarn test
This project uses TypeScript for static typing. Please add yourself to contributors according to all-contributors specification. You can use yarn all-contributors add {your-github-username} code,bug,...
.
Michal Kvasničák 💬 💻 🎨 📖 💡 🤔 👀 |
AlpacaGoesCrazy 💻 🐛 📖 |
Carlos Guerrero 💻 🐛 |
Samuel Marks 💻 🐛 |
This project follows the all-contributors specification. Contributions of any kind welcome!
MIT