aws api
![](https://i-blog.csdnimg.cn/blog_migrate/dcf3e02a2c850aaede835a4a251e5750.png)
随着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查询
我们需要做的下一件事是创建GraphQL查询,我们将从客户端使用它来查询API。
首先,我们创建一个目录来容纳我们的客户端代码。
$ 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
}
}`;
这只是一个简单的订阅查询,它将from
和body
消息字段返回。
6.从AWS控制台下载API Config
我们需要下载该应用程序的配置设置,以便它可以连接到我们的GraphQL API。
导航到AWS控制台中的AppSync部分。 选择您的API并下载Web配置设置。
![](https://i-blog.csdnimg.cn/blog_migrate/cd0e9613e29730e90593269865c8fc10.png)
您的下载区域中将有一个名为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
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/fa6dea1357d9346bff37ff5ab304d848.png)
您应该看到该消息立即出现在您的终端中。
![](https://i-blog.csdnimg.cn/blog_migrate/e1feb32db1566d5aa465a057e7184a58.png)
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
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/7333da3de7c43fbd94b233104ed355ba.png)
您应该看到更新已记录到浏览器的控制台中。
![](https://i-blog.csdnimg.cn/blog_migrate/da4daf003a28f08315b75cfceb712ab5.png)
12.结论
我们已经建立了一个无服务器的GraphQL API,它使用node.js和浏览器客户端通过websocket消耗实时更新。 30分钟的工作时间还不错!
尽管AppSync被提升为托管GraphQL API服务,但对我而言,其最佳功能是能够提供实时更新。 以前,您必须运行24/7服务器才能执行此操作。 现在,您可以节省无服务器的所有成本,并且无需管理服务器。
github上提供了此无服务器websockets示例的完整源代码。
如果您想了解有关构建实时无服务器应用程序的更多信息,请查看我即将在AWS AppSync上进行的培训课程《 全栈无服务器GraphQL应用程序》 。
最初发布于 andrewgriffithsonline.com 。
翻译自: https://hackernoon.com/build-a-realtime-serverless-graphql-api-with-websockets-on-aws-d9e553a997
aws api