From 75e997050aeb0c0a58289bfdd114db94a7cc6973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kvasnic=CC=8Ca=CC=81k?= Date: Mon, 7 Sep 2020 15:07:29 +0200 Subject: [PATCH 1/5] docs: initial gitbook docs --- .gitbook.yaml | 1 + docs/README.md | 17 +++++++++++++++++ docs/SUMMARY.md | 9 +++++++++ docs/quick-start.md | 14 ++++++++++++++ 4 files changed, 41 insertions(+) create mode 100644 .gitbook.yaml create mode 100644 docs/README.md create mode 100644 docs/SUMMARY.md create mode 100644 docs/quick-start.md diff --git a/.gitbook.yaml b/.gitbook.yaml new file mode 100644 index 0000000..768cfda --- /dev/null +++ b/.gitbook.yaml @@ -0,0 +1 @@ +root: ./docs/ \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..4f50a57 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,17 @@ +--- +title: Introduction +description: Serverless GraphQL subscriptions over WebSocket using AWS API Gateway v2 and AWS Lambda. +--- + +# Introduction + +Fully featured [Apollo Server Lambda](https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-lambda) compatible GraphQL server with GraphQL subscriptions over WebSocket support. + +Build real-time serverless AWS Lambda GraphQL services with WebSocket support over AWS API Gateway v2 or extend your existing HTTP GraphQL service with real-time capabilities. + +## Features + +- GraphQL subscriptions support using AWS API Gateway v2 +- HTTP GraphQL operations using AWS API Gateway v1 with [apollo-server-lambda](https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-lambda) compatibility + +![](./awsgql.gif 'Build real-time serverless GraphQL applications') diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md new file mode 100644 index 0000000..dc7b97a --- /dev/null +++ b/docs/SUMMARY.md @@ -0,0 +1,9 @@ +- [Introduction](./README.md) + +## Getting Started + +- [Quick start](./quick-start.md) + +## Examples + +## API diff --git a/docs/quick-start.md b/docs/quick-start.md new file mode 100644 index 0000000..c0b049a --- /dev/null +++ b/docs/quick-start.md @@ -0,0 +1,14 @@ +--- +title: Quick start +description: How to quickly start using Serverless GraphQL subscriptions in your project. +--- + +# Quick start + +## Installation + +```console +yarn add aws-lambda-graphql graphql graphql-subscriptions aws-sdk +# or +npm install aws-lambda-graphql graphql graphql-subscriptions aws-sdk +``` From 2a2e8e9bafd8b610fc298ef2031d27e85a8f5e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kvasnic=CC=8Ca=CC=81k?= Date: Mon, 7 Sep 2020 15:14:02 +0200 Subject: [PATCH 2/5] docs: add installation note --- docs/quick-start.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/quick-start.md b/docs/quick-start.md index c0b049a..f0f7242 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -12,3 +12,7 @@ yarn add aws-lambda-graphql graphql graphql-subscriptions aws-sdk # or npm install aws-lambda-graphql graphql graphql-subscriptions aws-sdk ``` + +{% hint style="info" %} +Note that `aws-sdk` is required only for local development, it's available in AWS Lambda environment by default when you deploy the app. +{% endhint %} From 43be93ff766df49826180d7adc0cb18fd6f99db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kvasnic=CC=8Ca=CC=81k?= Date: Mon, 7 Sep 2020 15:26:47 +0200 Subject: [PATCH 3/5] docs: add first application example --- docs/quick-start.md | 93 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/docs/quick-start.md b/docs/quick-start.md index f0f7242..25013cb 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -16,3 +16,96 @@ npm install aws-lambda-graphql graphql graphql-subscriptions aws-sdk {% hint style="info" %} Note that `aws-sdk` is required only for local development, it's available in AWS Lambda environment by default when you deploy the app. {% endhint %} + +## First application (broadcasting server) + +In this quick example we're going to build simple message broadcasting server that broadcasts messages received by `broadcastMessage` mutation to all subscribed clients. + +### Complete code + +First see the complete code. If you're interested in explanation continue reading below. + +```ts +import { + DynamoDBConnectionManager, + DynamoDBEventProcessor, + DynamoDBEventStore, + DynamoDBSubscriptionManager, + PubSub, + Server, +} from 'aws-lambda-graphql'; + +const eventStore = new DynamoDBEventStore(); +const eventProcessor = new DynamoDBEventProcessor(); +const subscriptionManager = new DynamoDBSubscriptionManager(); +const connectionManager = new DynamoDBConnectionManager({ + subscriptionManager, +}); +const pubSub = new PubSub({ eventStore }); + +const typeDefs = /* GraphQL */ ` + type Mutation { + """ + Sends a message to all subscribed clients + """ + broadcastMessage(message: String!): String! + } + + type Query { + """ + Dummy query so out server won't fail during instantiation + """ + dummy: String! + } + + type Subscription { + messageBroadcast: String! + } +`; + +const resolvers: { + Mutation: { + broadcastMessage: async ( + root, + { message }, + ) => { + await pubSub.publish('NEW_MESSAGE', { message }); + + return message; + }, + }, + Query: { + dummy: () => 'dummy', + }, + Subscription: { + messageBroadcast: { + // rootValue is same as the event published above ({ message: string }) + // but our subscription should return just a string, so we're going to use resolve + // to extract message from an event + resolve: rootValue => rootValue.message, + subscribe: pubSub.subscribe('NEW_MESSAGE'), + }, + }, +}; + +const server = new Server({ + // accepts all the apollo-server-lambda options and adds few extra options + // provided by this package + connectionManager, + eventProcessor, + resolvers, + subscriptionManager, + typeDefs, +}); + +export const handleWebSocket = server.createWebSocketHandler(); +export const handleHTTP = server.createHttpHandler(); +// this creates dynamodb event handler so we can send messages to subscribed clients +export const handleEvents = server.createEventHandler(); +``` + +{% hint style="info" %} +Exported handlers need to be mapped to their event sources. `handleWebSocket` needs to be mapped to `API Gateway v2` event source, `handleHTTP` to `API Gateway v1` event source and `handleEvents` to `DynamoDB Stream` event source. + +See [serverless.yml](./serverless.yml) template to see how to setup event sources. +{% endhint %} From afd6bfccd165e233c70e03bb179478b02e51dd69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kvasnic=CC=8Ca=CC=81k?= Date: Mon, 7 Sep 2020 21:23:53 +0200 Subject: [PATCH 4/5] docs: add simple getting started guide --- docs/SUMMARY.md | 28 ++- docs/getting-started/00-installation.md | 17 ++ docs/getting-started/01-first-service.md | 10 ++ ...-connection-and-subscription-management.md | 34 ++++ docs/getting-started/03-event-store.md | 30 ++++ docs/getting-started/04-graphql-schema.md | 43 +++++ docs/getting-started/05-pubsub.md | 80 +++++++++ .../06-event-handlers.md} | 65 +++---- docs/getting-started/07-deploy.md | 166 ++++++++++++++++++ docs/getting-started/08-test.md | 37 ++++ 10 files changed, 467 insertions(+), 43 deletions(-) create mode 100644 docs/getting-started/00-installation.md create mode 100644 docs/getting-started/01-first-service.md create mode 100644 docs/getting-started/02-connection-and-subscription-management.md create mode 100644 docs/getting-started/03-event-store.md create mode 100644 docs/getting-started/04-graphql-schema.md create mode 100644 docs/getting-started/05-pubsub.md rename docs/{quick-start.md => getting-started/06-event-handlers.md} (53%) create mode 100644 docs/getting-started/07-deploy.md create mode 100644 docs/getting-started/08-test.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index dc7b97a..53ea65f 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -2,8 +2,32 @@ ## Getting Started -- [Quick start](./quick-start.md) +- [Installation](./getting-started/00-installation.md) +- [First service](./getting-started/01-first-server.md) +- [Connection and subscription management](./getting-started/02-connection-and-subscription-management.md) +- [Event store](./getting-started/03-event-store.md) +- [GraphQL Schema](./getting-started/04-graphql-schema.md) +- [PubSub](./getting-started/05-pubsub.md) +- [WebSocket/HTTP and event processing handlers](./getting-started/06-event-handlers.md) +- [Deploy](./getting-started/07-deploy.md) +- [Test](./getting-started/08-test.md) -## Examples +## Advanced + +- [How it works](./advanced/how-it-works.md) +- [Serverless Support](./advanced/serverless-support.md) +- [PubSub instance in GraphQL context](./advanced/pub-sub-in-graphql-context.md) ## API + +- [DynamoDBConnectionManager](./api/DynamoDBConnectionManager.md) +- [DynamoDBEventProcessor](./api/DynamoDBEventProcessor.md) +- [DynamoDBEventStore](./api/DynamoDBEventStore.md) +- [DynamoDBSubscriptionManager](./api/DynamoDBSubscriptionManager.md) +- [MemoryEventProcessor](./api/MemoryEventProcessor.md) +- [MemoryEventStore](./api/MemoryEventStore.md) +- [MemorySubscriptionManager](./api/MemorySubscriptionManager.md) +- [PubSub](./api/PubSub.md) +- [RedisConnectionManager](./api/RedisConnectionManager.md) +- [RedisSubscriptionManager](./api/RedisSubscriptionManager.md) +- [WebSocketConnectionManager](./api/WebSocketConnectionManager.md) diff --git a/docs/getting-started/00-installation.md b/docs/getting-started/00-installation.md new file mode 100644 index 0000000..74936a6 --- /dev/null +++ b/docs/getting-started/00-installation.md @@ -0,0 +1,17 @@ +--- +title: Installation +--- + +# Installation + +```console +yarn add aws-lambda-graphql graphql graphql-subscriptions aws-sdk +# or +npm install aws-lambda-graphql graphql graphql-subscriptions aws-sdk +``` + +{% hint style="info" %} +Note that `aws-sdk` is required only for local development, it's available in AWS Lambda environment by default when you deploy the app. +{% endhint %} + +Now when we've our dependencies in place, we can go through our first real-time GraphQL service. diff --git a/docs/getting-started/01-first-service.md b/docs/getting-started/01-first-service.md new file mode 100644 index 0000000..7e47a1c --- /dev/null +++ b/docs/getting-started/01-first-service.md @@ -0,0 +1,10 @@ +--- +title: First service +description: How to implement your first real-time serverless GraphQL service. +--- + +# First service + +Now we'll introduce a few concepts so you can understand how the GraphQL subscriptions over API Gateway v2 work. To do that we're going to implement a simple GraphQL service that broadcasts messages to subscribed clients. + +We're going to slowly walk through concepts which are necessary for any real-time GraphQL application in next sections. diff --git a/docs/getting-started/02-connection-and-subscription-management.md b/docs/getting-started/02-connection-and-subscription-management.md new file mode 100644 index 0000000..51973e3 --- /dev/null +++ b/docs/getting-started/02-connection-and-subscription-management.md @@ -0,0 +1,34 @@ +--- +title: 'Connection and subscription management' +description: How to set up connection and subscription management. +--- + +# Connection and subscription management + +Our GraphQL server needs to know what subscriptions are clients subscribed to and how to communicate with those clients. In order to do that the server uses [Connection manager](../../packages/aws-lambda-graphql/src/types/connections.ts) and [Subscription manager](../../packages/aws-lambda-graphql/src/types/subscriptions.ts). + +## Connection manager + +The purpose of Connection manager is to register or unregister all the connections which have connected to your service over AWS API Gateway v2. + +## Subscription manager + +Each client that subscribes to some GraphQL subscription is managed by Suscription manager. Subscription manager stores the information about connection and GraphQL document used to subscribe to the operation by the given connection. + +## Put together + +We'll use [`DynamoDBConnectionManager`](../api/DynamoDBConnectionManager.md) and [`DynamoDBSubscriptionManager`](../api/DynamoDBSubscriptionManager.md) to manage connections and subscriptions. + +```js +import { + DynamoDBConnectionManager, + DynamoDBSubscriptionManager, +} from 'aws-lambda-graphql'; + +const subscriptionManager = new DynamoDBSubscriptionManager(); +const connectionManager = new DynamoDBConnectionManager({ + subscriptionManager, +}); +``` + +In next section we're going to create an event store so we can store published messages and process them later. diff --git a/docs/getting-started/03-event-store.md b/docs/getting-started/03-event-store.md new file mode 100644 index 0000000..095bd88 --- /dev/null +++ b/docs/getting-started/03-event-store.md @@ -0,0 +1,30 @@ +--- +title: Event store +description: How to set up an event store so we can process events published by connected clients. +--- + +# Event store + +Each client can publish messages that can be processed and sent to subscribed clients. + +[Event store](../../packages/aws-lambda-graphql/src/types/events.md) is responsible for storing those events to storage that can be used as an event source for our event processing handler. + +## Put together + +We'll use [`DynamoDBEventStore`](../api/DynamoDBEventStore.md) that stores the events in DynamoDB table which will be used as an event source for our event processing lambda by leveraging DynamoDB streams. + +```js +import { + DynamoDBConnectionManager, + DynamoDBEventStore, + DynamoDBSubscriptionManager, +} from 'aws-lambda-graphql'; + +const eventStore = new DynamoDBEventStore(); +const subscriptionManager = new DynamoDBSubscriptionManager(); +const connectionManager = new DynamoDBConnectionManager({ + subscriptionManager, +}); +``` + +That's it for now. Our `eventStore` will be used to publish messages to all subscribed clients. In next section we'll create a simple GraphQL schema for our service. diff --git a/docs/getting-started/04-graphql-schema.md b/docs/getting-started/04-graphql-schema.md new file mode 100644 index 0000000..1e3447e --- /dev/null +++ b/docs/getting-started/04-graphql-schema.md @@ -0,0 +1,43 @@ +--- +title: GraphQL schema +description: Define GraphQL schema for your first service. +--- + +# GraphQL schema + +Our service needs a GraphQL schema, so we'll create one. Each client can subscribe to broadcast by `messageBroadcast` GraphQL subscription and is able to broadcast any message to all clients event itself by `broadcastMessage` GraphQL mutation. + +## Put together + +```js +import { + DynamoDBConnectionManager, + DynamoDBEventStore, + DynamoDBSubscriptionManager, +} from 'aws-lambda-graphql'; + +const eventStore = new DynamoDBEventStore(); +const subscriptionManager = new DynamoDBSubscriptionManager(); +const connectionManager = new DynamoDBConnectionManager({ + subscriptionManager, +}); + +const typeDefs = /* GraphQL */ ` + type Mutation { + broadcastMessage(message: String!): String! + } + + type Query { + """ + Dummy query so out server won't fail during instantiation + """ + dummy: String! + } + + type Subscription { + messageBroadcast: String! + } +`; +``` + +In next section we'll create a PubSub instance and give the schema a logic so client can subscribe to messages or broadcast them. diff --git a/docs/getting-started/05-pubsub.md b/docs/getting-started/05-pubsub.md new file mode 100644 index 0000000..3091f16 --- /dev/null +++ b/docs/getting-started/05-pubsub.md @@ -0,0 +1,80 @@ +--- +title: PubSub +description: How to create PubSub instance in order to send and subscribe to messages. +--- + +# PubSub + +Any GraphQL service that wants to offer GraphQL subscriptions needs to use [PubSub](../api/PubSub.md) in order to publish and subscribe to messages (events). PubSub uses [Event store](./03-event-store.md) to store published messages. They are later picked up from event source by [Event processor](./06-event-handlers.md). + +## Put together + +Let's import PubSub and connect it to [Event store](./03-event-store.md) we created before. Then we use the `pubSub` instance in our GraphQL schema resolvers. + +```js +import { + DynamoDBConnectionManager, + DynamoDBEventStore, + DynamoDBSubscriptionManager, + PubSub, +} from 'aws-lambda-graphql'; + +const eventStore = new DynamoDBEventStore(); +const subscriptionManager = new DynamoDBSubscriptionManager(); +const connectionManager = new DynamoDBConnectionManager({ + subscriptionManager, +}); +const pubSub = new PubSub({ + eventStore, + // optional, if you don't want to store messages to your store as JSON + // serializeEventPayload: false, +}); + +const typeDefs = /* GraphQL */ ` + type Mutation { + broadcastMessage(message: String!): String! + } + + type Query { + """ + Dummy query so out server won't fail during instantiation + """ + dummy: String! + } + + type Subscription { + messageBroadcast: String! + } +`; + +const resolvers: { + Mutation: { + broadcastMessage: async ( + root, + { message }, + ) => { + await pubSub.publish('NEW_MESSAGE', { message }); + + return message; + }, + }, + Query: { + dummy: () => 'dummy', + }, + Subscription: { + messageBroadcast: { + // rootValue is same as the event published above ({ message: string }) + // but our subscription should return just a string, so we're going to use resolve + // to extract message from an event + resolve: rootValue => rootValue.message, + subscribe: pubSub.subscribe('NEW_MESSAGE'), + }, + }, +}; +``` + +{% hint style="info" %} +⚠️ Be careful! By default `PubSub` serializes event payload to JSON. If you don't want this behaviour, set `serializeEventPayload` to `false` on your `PubSub` instance. +{% endhint %} + +Now our schema is ready, so let's create a GraphQL server and expose it's handlers to AWS Lambda in the next section. diff --git a/docs/quick-start.md b/docs/getting-started/06-event-handlers.md similarity index 53% rename from docs/quick-start.md rename to docs/getting-started/06-event-handlers.md index 25013cb..59c46a0 100644 --- a/docs/quick-start.md +++ b/docs/getting-started/06-event-handlers.md @@ -1,31 +1,21 @@ --- -title: Quick start -description: How to quickly start using Serverless GraphQL subscriptions in your project. +title: Event handlers +description: How to expose AWS Lambda handlers for our real-time GraphQL service. --- -# Quick start +# Event handlers -## Installation +AWS Lambda needs a handler, function that processes an event received by our lambda function. Event handlers are exposed from [Server](../api/Server.md) by calling the create methods for HTTP, WebSocket or event processing handlers. -```console -yarn add aws-lambda-graphql graphql graphql-subscriptions aws-sdk -# or -npm install aws-lambda-graphql graphql graphql-subscriptions aws-sdk -``` - -{% hint style="info" %} -Note that `aws-sdk` is required only for local development, it's available in AWS Lambda environment by default when you deploy the app. -{% endhint %} - -## First application (broadcasting server) - -In this quick example we're going to build simple message broadcasting server that broadcasts messages received by `broadcastMessage` mutation to all subscribed clients. +## Put together -### Complete code +We have functioning GraphQL schema with resolvers for `broadcastMessage` GraphQL mutation and `messageBroadcast` GraphQL subscription. We need to create a server that glues together all the pieces we created along our journey and exposes handlers: -First see the complete code. If you're interested in explanation continue reading below. +- `handleWebSocket` for `AWS API Gateway v2` events +- `handleHTTP` for `AWS API Gateway v1` events +- `handeEvents` for `DynamoDB Streams` events -```ts +```js import { DynamoDBConnectionManager, DynamoDBEventProcessor, @@ -45,22 +35,19 @@ const pubSub = new PubSub({ eventStore }); const typeDefs = /* GraphQL */ ` type Mutation { - """ - Sends a message to all subscribed clients - """ - broadcastMessage(message: String!): String! - } - - type Query { - """ - Dummy query so out server won't fail during instantiation - """ - dummy: String! - } - - type Subscription { - messageBroadcast: String! - } + broadcastMessage(message: String!): String! + } + + type Query { + """ + Dummy query so out server won't fail during instantiation + """ + dummy: String! + } + + type Subscription { + messageBroadcast: String! + } `; const resolvers: { @@ -104,8 +91,4 @@ export const handleHTTP = server.createHttpHandler(); export const handleEvents = server.createEventHandler(); ``` -{% hint style="info" %} -Exported handlers need to be mapped to their event sources. `handleWebSocket` needs to be mapped to `API Gateway v2` event source, `handleHTTP` to `API Gateway v1` event source and `handleEvents` to `DynamoDB Stream` event source. - -See [serverless.yml](./serverless.yml) template to see how to setup event sources. -{% endhint %} +Our server is finished 🎉. In next section we'll deploy our service. diff --git a/docs/getting-started/07-deploy.md b/docs/getting-started/07-deploy.md new file mode 100644 index 0000000..3bef830 --- /dev/null +++ b/docs/getting-started/07-deploy.md @@ -0,0 +1,166 @@ +--- +title: Deploy +description: How to deploy our Graphl service using serverless framework. +--- + +# Deploy + +In order to test our service we need to deploy it to AWS. We'll use [Serverless framework](https://serverless.com) to do so (also you can find out about Serverless offline support in [Serverless Support](../advanced/serverless-support.md)). + +Our `serverless.yml` file should look like this: + +```yaml +service: graphql-server-demo # NOTE: update this with your service name + +provider: + name: aws + runtime: nodejs10.x + region: eu-central-1 # NOTE: change with your preferred region + + iamRoleStatements: + - Effect: Allow + Action: + - execute-api:ManageConnections + Resource: 'arn:aws:execute-api:*:*:*/development/POST/@connections/*' + - Effect: Allow + Action: + - dynamodb:DeleteItem + - dynamodb:GetItem + - dynamodb:PutItem + - dynamodb:UpdateItem + Resource: !GetAtt ConnectionsDynamoDBTable.Arn + - Effect: Allow + Action: + - dynamodb:DescribeStream + - dynamodb:GetRecords + - dynamodb:GetShardIterator + - dynamodb:ListStreams + Resource: !GetAtt EventsDynamoDBTable.StreamArn + - Effect: Allow + Action: + - dynamodb:PutItem + Resource: !GetAtt EventsDynamoDBTable.Arn + - Effect: Allow + Action: + - dynamodb:BatchWriteItem + - dynamodb:DeleteItem + - dynamodb:GetItem + - dynamodb:PutItem + - dynamodb:Query + - dynamodb:Scan + Resource: !GetAtt SubscriptionsDynamoDBTable.Arn + - Effect: Allow + Action: + - dynamodb:BatchWriteItem + - dynamodb:DeleteItem + - dynamodb:GetItem + - dynamodb:PutItem + Resource: !GetAtt SubscriptionOperationsDynamoDBTable.Arn + +functions: + wsHandler: + handler: index.handleWebSocket + events: + - websocket: + route: $connect + - websocket: + route: $disconnect + - websocket: + route: $default + eventProcessorHandler: + handler: index.handleEvents + events: + - stream: + enabled: true + type: dynamodb + arn: + Fn::GetAtt: [EventsDynamoDBTable, StreamArn] + # this one is optional (if you want to support HTTP) + httpHandler: + handler: index.handleHTTP + events: + - http: + path: / + method: any + cors: true + +resources: + Resources: + ConnectionsDynamoDBTable: + Type: AWS::DynamoDB::Table + Properties: + # see DynamoDBConnectionManager + TableName: Connections + AttributeDefinitions: + - AttributeName: id + AttributeType: S + BillingMode: PAY_PER_REQUEST + KeySchema: + # connection id + - AttributeName: id + KeyType: HASH + # This one is optional (all connections have 2 hours of lifetime in ttl field but enabling TTL is up to you) + TimeToLiveSpecification: + AttributeName: ttl + Enabled: true + + SubscriptionsDynamoDBTable: + Type: AWS::DynamoDB::Table + Properties: + # see DynamoDBSubscriptionManager + TableName: Subscriptions + AttributeDefinitions: + - AttributeName: event + AttributeType: S + - AttributeName: subscriptionId + AttributeType: S + BillingMode: PAY_PER_REQUEST + KeySchema: + - AttributeName: event + KeyType: HASH + - AttributeName: subscriptionId + KeyType: RANGE + # This one is optional (all subscriptions have 2 hours of lifetime in ttl field but enabling TTL is up to you) + TimeToLiveSpecification: + AttributeName: ttl + Enabled: true + + SubscriptionOperationsDynamoDBTable: + Type: AWS::DynamoDB::Table + Properties: + # see DynamoDBSubscriptionManager + TableName: SubscriptionOperations + AttributeDefinitions: + - AttributeName: subscriptionId + AttributeType: S + BillingMode: PAY_PER_REQUEST + KeySchema: + - AttributeName: subscriptionId + KeyType: HASH + # This one is optional (all subscription operations have 2 hours of lifetime in ttl field but enabling TTL is up to you) + TimeToLiveSpecification: + AttributeName: ttl + Enabled: true + + EventsDynamoDBTable: + Type: AWS::DynamoDB::Table + Properties: + # see DynamoDBEventStore + TableName: Events + KeySchema: + - AttributeName: id + KeyType: HASH + BillingMode: PAY_PER_REQUEST + # see ISubscriptionEvent + AttributeDefinitions: + - AttributeName: id + AttributeType: S + StreamSpecification: + StreamViewType: NEW_IMAGE + # This one is optional (all events have 2 hours of lifetime in ttl field but enabling TTL is up to you) + TimeToLiveSpecification: + AttributeName: ttl + Enabled: true +``` + +Now we've deployed our first GraphQL service with real-time capabilities. Let's test it by creating a simple client app described in next section. diff --git a/docs/getting-started/08-test.md b/docs/getting-started/08-test.md new file mode 100644 index 0000000..c154731 --- /dev/null +++ b/docs/getting-started/08-test.md @@ -0,0 +1,37 @@ +--- +title: Test +description: Create a simple GraphQL client to test our service. +--- + +# Test + +🎉 Congratulations you arrived to final section in our getting started guide. Your service is deployed and you received a AWS API Gateway v2 URI in the output of deployment from previous section. You'll need that URI so your first GraphQL client is able to connect to your service. + +But firstly, we need few dependencies. + +```console +yarn add apollo-link-ws apollo-cache-inmemory apollo-client subscriptions-transport-ws +# or +npm install apollo-link-ws apollo-cache-inmemory apollo-client subscriptions-transport-ws +``` + +Now with these dependencies in place, we can implement an easy client that connects to our service. Rest is app to you 🙂 + +```js +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', // please provide the uri of the api gateway v2 endpoint + { lazy: true, reconnect: true }, + null, + [], // this one is necessary so AWS API Gateway v2 won't error with Sec-WebSocket-Protocol +); +const link = new WebSocketLink(wsClient); +const client = new ApolloClient({ + cache: new InMemoryCache(), + link, +}); +``` From 72ee78dc3cb0382a66b2103b92b8f46951fa0257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kvasnic=CC=8Ca=CC=81k?= Date: Mon, 7 Sep 2020 21:29:22 +0200 Subject: [PATCH 5/5] docs: fix first service document page url --- docs/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 53ea65f..9fbd8fb 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -3,7 +3,7 @@ ## Getting Started - [Installation](./getting-started/00-installation.md) -- [First service](./getting-started/01-first-server.md) +- [First service](./getting-started/01-first-service.md) - [Connection and subscription management](./getting-started/02-connection-and-subscription-management.md) - [Event store](./getting-started/03-event-store.md) - [GraphQL Schema](./getting-started/04-graphql-schema.md)