在AWS上使用Websocket构建实时的无服务器GraphQL API

随着AWS AppSync的发布,我们终于可以在AWS上创建实时的无服务器应用程序。 以前,您被迫启动EC2实例以创建Websocket连接,因为AWS Lambda不支持它们。

在本教程中,您将学习如何使用AWS AppSync构建简单的GraphQL API。 然后,您将使用香草javascript (无框架)编写一个客户端应用程序,该应用程序通过websockets接收实时更新。 让我们开始吧!

1.设定

继续并安装无服务器框架cli,我们将使用它来部署AppSync GraphQL API并为我们的项目创建一个新目录。

$ npm install -g serverless $ mkdir realtime-chat
$ cd realtime-chat

2.创建GraphQL模式

我们将为我们的聊天应用程序定义一个基本的GraphQL模式。

schema {
query: Query
mutation: Mutation
subscription: Subscription
}
type Subscription {
inbox(to: String): Page
@aws_subscribe (mutations: ["message"])
}
type Mutation {
message(body: String!, to: String!): Page!
}
type Message {
from: String!
to: String!
body: String!
sentAt: String!
}
type Query {
me: String
}

除实时订阅外的标准GraphQL模式,它使用特殊语法向AWS AppSync指示要订阅哪个突变( @aws_subscribe(mutations: ["message"]) ),在这种情况下为message突变。

3.创建映射模板

现在我们定义了架构,我们需要为其添加解析器。 如果您期望需要编写lambda函数,那您将错了! AppSync引入了映射模板的概念,该模板将客户端请求转换为后备存储(DynamoDB,elasticsearch等)可以理解的一个,然后将响应再次转换回客户端。

为简单起见,我们创建了一个没有数据库的API。 AppSync提供了一种称为本地解析器的特殊类型的解析器,该解析器不保留请求数据,而只是将其中继到当时存在的任何订户。

让我们创建一个目录来容纳我们的映射模板。

$ mkdir mapping-templates

然后,让我们在一个名为mapping-templates/Message.request.vtl的文件中创建用于message变异的请求模板,该文件将从变异请求中提取字段。

{
"version": "2017-02-28",
"payload": {
"body": "${context.arguments.body}",
"from": "${context.identity.username}",
"to": "${context.arguments.to}",
"sentAt": "$util.time.nowISO8601()"
}
}

对于响应,我们仅使用标准转发模板。 创建一个包含以下内容的文件名为mapping-templates/ForwardResult.response.vtl

$util.toJson($context.result)

您的文件夹结构现在应如下所示:

$ tree mapping-templates mapping-templates ├── ForwardResult.response.vtl └── Message.request.vtl

4.使用无服务器框架部署AppSync GraphQL API

现在,我们需要为无服务器框架创建一个配置文件以配置我们的API。 为了做到这一点,我们将使用Serverless-AppSync-Plugin

npm安装它。

$ npm install --dev serverless-appsync-plugin

然后创建具有以下内容的serverless.yml文件。

---
service: realtime-chat
frameworkVersion: ">=1.21.0 <2.0.0"
plugins:
- serverless-appsync-plugin
provider:
name: aws
region: eu-west-1
custom:
awsAccountId: ${env:AWS_ACCOUNT_ID}
appSync:
name: realtimeChat
apiKey: ${env:APPSYNC_API_KEY}
apiId: ${env:APPSYNC_API_ID}
authenticationType: API_KEY
schema: schema/schema.graphql
serviceRole: "AppSyncServiceRole" # AppSyncServiceRole is a role defined by amazon and available in all accounts
mappingTemplatesLocation: mapping-templates
mappingTemplates:
- dataSource: Chat
type: Mutation
field: message
request: Message.request.vtl
response: ForwardResult.response.vtl
- dataSource: Chat
type: Subscription
field: inbox
request: Message.request.vtl
response: ForwardResult.response.vtl
dataSources:
- type: NONE # use an AppSync local resolver
name: Chat
description: 'Chat relay'

如您所见,我们将数据源类型设置为NONE以便使用本地解析器,因为我们不想将聊天消息保留在数据库中,而只是将其转发给其他侦听更新的客户端。

我们的serverless.yml配置包含一些我们必须提供的环境变量。 让我们创建一个.env文件,其中包含我们的AWS账户ID并动态填充其他变量。

# .env
export AWS_ACCOUNT_ID=123456789
export APPSYNC_API_ID=$(aws appsync list-graphql-apis \
--query 'graphqlApis[?name==`realtimeChat`].apiId' \
--output text >/dev/null 2>&1)
export APPSYNC_API_KEY=$(aws appsync list-api-keys \
--api-id "$APPSYNC_API_ID" \
--query 'apiKeys[0].id' \
--output text >/dev/null 2>&1)

现在,我们准备使用一个命令来部署我们的API:

恭喜你! 您刚刚部署了具有实时支持的GraphQL API。

5.为客户端应用程序创建GraphQL查询

接下来需要做的是创建将用于客户端查询API的GraphQL查询。

首先,我们创建一个目录来容纳我们的客户端代码。

$ mkdir src

然后让我们为查询创建一个目录。

$ mkdir src/graphql

src/graphql/inboxSubscription.js为我们的订阅查询创建一个文件,其内容如下:

import gql from 'graphql-tag';
export default gql`
subscription Inbox($to: String) {
inbox(to: $to) {
from
body
}
}`;

这只是一个简单的订阅查询,它将frombody消息字段返回。

6.从AWS控制台下载API Config

我们需要下载该应用程序的配置设置,以便它可以连接到我们的GraphQL API。

导航到AWS控制台中的AppSync部分。 选择您的API并下载Web配置设置。

您的下载区域中将有一个名为AppSync.js的文件。 将其移动到src目录,并将其重命名为config.js

如果您保留了用于将API保护为API_KEY的默认选项,则下载的配置文件应如下所示。

export default {
"graphqlEndpoint": " https://xxxx.appsync-api.eu-west-1.amazonaws.com/graphql ",
"region": "eu-west-1",
"authenticationType": "API_KEY",
"apiKey": "xxxxxxxxxxxxxxxxxxxxxxxxx"
}

7.同构的Vanilla JavaScript客户端代码,用于订阅实时API更新

我们将创建一个同构客户端,该客户端可以在浏览器中运行,也可以通过终端中的node.js运行。

首先,让我们安装所需的依赖项。

$ npm install -s apollo-cache-inmemory apollo-client apollo-link aws-appsync aws-sdk es6-promise graphql graphql-cli graphql-tag isomorphic-fetch ws

然后,为应用程序创建一个入口点。

您的应用程序源代码目录现在应包含以下内容。

$ tree src
src
├── config.js
├── graphql
│ └── inboxSubscription.js
└── index.js

将以下代码粘贴到index.js文件中:

const RECIPIENT = 'Bobby';
if (!global.WebSocket) {
global.WebSocket = require('ws');
}
if (!global.window) {
global.window = {
setTimeout: setTimeout,
clearTimeout: clearTimeout,
WebSocket: global.WebSocket,
ArrayBuffer: global.ArrayBuffer,
addEventListener: function () { },
navigator: { onLine: true }
};
}
if (!global.localStorage) {
global.localStorage = {
store: {},
getItem: function (key) {
return this.store[key];
},
setItem: function (key, value) {
this.store[key] = value;
},
removeItem: function (key) {
delete this.store[key];
}
};
}
require('es6-promise').polyfill();
require('isomorphic-fetch');
// Require config file downloaded from AWS console with endpoint and auth info
const AppSyncConfig = require('./config').default;
const AWSAppSyncClient = require('aws-appsync').default;
import InboxSubscription from './graphql/inboxSubscription';
// Set up Apollo client
const client = new AWSAppSyncClient({
url: AppSyncConfig.graphqlEndpoint,
region: AppSyncConfig.region,
auth: {
type: AppSyncConfig.authenticationType,
apiKey: AppSyncConfig.apiKey,
}
});
client.hydrated().then(function (client) {
const observable = client.subscribe({ query: InboxSubscription, variables: { to: RECIPIENT } });
const realtimeResults = function realtimeResults(data) {
console.log('realtime data: ', data);
};
observable.subscribe({
next: realtimeResults,
complete: console.log,
error: console.log,
});
});

对于这个简单的演示,我们已经将接收者硬编码为Bobby但是显然您希望对实际应用程序保持动态。

8. Node.js客户端应用程序构建过程

至此,我们已经为websockets客户端编写了所有源代码,我们只需要实现构建过程即可。 由于源代码使用es6功能,因此我们需要使用babel进行编译。

安装我们需要的开发依赖项。

$ npm install --save-dev babel-cli babel-preset-es2015 rimraf webpack webpack-cli webpack-dev-server

现在,让我们构建应用程序。

$ rimraf build/ && babel ./src --out-dir build/ --ignore ./node_modules,./.babelrc,./package.json,./npm-debug.log --copy-file

9. Node.js客户端应用程序

现在,让我们在node.js中运行我们的应用程序。

$ node build/index.js

导航到AWS控制台中AppSync API中的queries页面,然后运行以下graphQL变体来触发一些udpate。

mutation Message {
message(to: "Bobby", body: "Yo node!") {
body
to
from
sentAt
}
}

您应该看到该消息立即出现在您的终端中。

10.浏览器客户端应用程序构建过程

请记住,我们编写的代码是同构的。 这意味着它在浏览器中的运行也一样。

首先安装我们需要的开发依赖项。

$ npm install --save-dev webpack webpack-cli webpack-dev-server

我们将使用webpack来运行构建过程,因此我们需要为其创建配置文件。 使用以下内容在项目的路径处创建一个名为webpack.config.js的文件。

const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};

由于网络服务器将通过dist目录提供资产,因此我们需要添加一个index.html文件,其中包括webpack将生成的bundle.js文件。 在dist/index.html上创建一个包含以下内容的文件。

<!DOCTYPE html>
<html>
<head>
<title>AWS Serverless Websockets Demo</title>
</head>
<body>
</body>
<script type="text/javascript" src="bundle.js"></script>
</html>

10.浏览器客户端应用程序

运行以下命令,这将从dist目录启动webpack-dev-server服务资产。

$ webpack-dev-server --mode development --content-base dist/

然后在浏览器中导航至http://localhost:8080并打开开发工具,因为我们会将数据记录到控制台中。

导航到AWS控制台中AppSync API中的queries页面,然后运行另一个graphQL变异来触发更新。

mutation Message {
message(to: "Bobby", body: "hello browser!") {
body
to
from
sentAt
}
}

您应该看到更新已记录到浏览器的控制台中。

12.结论

我们已经建立了一个无服务器的GraphQL API,它使用node.js和浏览器客户端通过websocket消耗实时更新。 30分钟的工作时间还不错!

尽管AppSync被提升为托管GraphQL API服务,但对我而言,其最佳功能是能够提供实时更新。 以前,您必须运行24/7的服务器才能执行此操作。 现在,您可以节省无服务器的所有成本,并且无需管理服务器。

github上提供了此无服务器websockets示例的完整源代码。

如果您想了解有关构建实时无服务器应用程序的更多信息,请查看我即将举行的培训课程, 即基于AWS AppSync的全栈无服务器GraphQL应用程序

最初发布于 andrewgriffithsonline.com

From: https://hackernoon.com/build-a-realtime-serverless-graphql-api-with-websockets-on-aws-d9e553a997

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值