参考资料

  • https://docs.amazonaws.cn/appsync/latest/devguide/quickstart-launch-a-sample-schema.html
  • AWS 上使用 GraphQL 实现 API 现代化时的考虑事项

appsync的核心概念

  • 模式(schema),每个 GraphQL API 都由一个使用 GraphQL 模式定义语言(SDL)编写的模式定义。在schema中添加新类型时,可以配置dynamodb连接(自动设置适当主键、排序键和索引)

    aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

  • 解析器(reslover),解析器是将 GraphQL 请求转换为数据源可以理解的格式的函数。解析器具有可以访问上下文对象并定义转换和执行逻辑的请求和响应模板。

    以下是快速入门示例中的create event解析器

    aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

  • 创建资源(resources),从schema中的类型快速创建 dynamodb 表,自动连接常见操作的查询和变换。

  • 函数,针对数据源进行的单操作,包括请求映射模板响应映射模板,不同于之前解析程序中的单元解析程序。可以复用并通过管道解析程序进行组合

  • 数据源,data source可以有多种选择。appsync访问的独享

    aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

  • 设置,可以配置认证方式等(默认授权模式为 API_KEY)

    aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

  • 查询(query),用于编写,验证和测试GraphQL操作的内置工具

    aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

具体说说查询(query)界面

  • explorer是图形化的GraphQL编辑器,和中间的GraphQL语句双向绑定

  • 在GraphQL可以指定操作,参数和返回值。支持autoid设置dynamodb上的分区键

    aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

从dynamodb中生成schema

GraphQL 有三项顶级操作:

  • 查询 – 只读提取
  • 更改 – 写入,然后提取
  • 订阅 – 用于接收数据的长期活动连接

我们需要做的事情就是

  • 设计schema模型,描述数据对象
  • 编写请求GraphQL,描述请求参数和响应
  • 得到响应的数据,进行下一步处理

利用wizard创建一个带有3个字段的表

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

之后会自动创建dynamodb表,此处指定id为分区键。

查看自动按照表结构生成的schema比较复杂,修改为以下形式

  • 描述数据对象,包括id,title和content三个字段
  • 包括查询,变更和订阅行为
  • 每种行为包括参数和返回类型
  • type除了指定标量类型外还有对象类型,可以嵌套
type MyModelType {id: ID!title: Stringcontent: String
}type MyModelTypeConnection {items: [MyModelType]nextToken: String
}type Mutation {createMyModelType(title: String!, content: String): MyModelTypeupdateMyModelType(id: ID!, title: String!, content: String): MyModelTypedeleteMyModelType(id: ID!): MyModelType
}type Query {getMyModelType(id: ID!): MyModelTypelistMyModelTypes(limit: Int, nextToken: String): MyModelTypeConnection
}type Subscription {onCreateMyModelType(id: ID, title: String, content: String): MyModelType@aws_subscribe(mutations: ["createMyModelType"])onUpdateMyModelType(id: ID, title: String, content: String): MyModelType@aws_subscribe(mutations: ["updateMyModelType"])onDeleteMyModelType(id: ID, title: String, content: String): MyModelType@aws_subscribe(mutations: ["deleteMyModelType"])
}

将reslover修改为如下,直接指定创建对象的参数

  • 主键自动升序插入
  • 字段从$context.arguments中获取
{"version": "2017-02-28","operation": "PutItem","key": {"id": $util.dynamodb.toDynamoDBJson($util.autoId()),},"attributeValues": {"title": { "S": "$context.arguments.title" },"content": { "S": "$context.arguments.content" }},"condition": {"expression": "attribute_not_exists(#id)","expressionNames": {"#id": "id",},},
}

执行创建对象如下

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

执行查询操作

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

从头创建一个schema

从头创建一个api,此时没有schema和datasource

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

前端最经典的demo要数todo了,官方为我们提供了一个todo的样例schema

  • 创建todo list数据模型
  • 主要数据为todo项目,包括名称,描述,优先级和状态
  • 每个todo项目可以增加多个comments
  • todo项目和comments可以进行增删改查操作

简单查询

schema {query:Querymutation: Mutation
}type Todo {id: ID!name: Stringdescription: Stringpriority: Intstatus: TodoStatus
}enum TodoStatus {donepending
}type Query {getTodos: [Todo]
}

修改行为

schema {query:Querymutation: Mutation
}
...
type Mutation {addTodo(id: ID!, name: String, description: String, priority: Int, status: TodoStatus): Todo
}

修改查询增加分页功能

type Query {getTodos(limit: Int, nextToken: String): TodoConnection
}type TodoConnection {todos: [Todo]nextToken: String
}

增加评论类型

type Comment {todoid: ID!commentid: String!content: String
}
type Todo {id: ID!name: Stringdescription: Stringpriority: Intstatus: TodoStatuscomments: [Comment]
}

最终创建的schema如下

type Comment {todoid: ID!commentid: String!content: String
}type Mutation {addTodo(id: ID!,name: String,description: String,priority: Int,status: TodoStatus): TodoaddComment(todoid: ID!, content: String): Comment
}type Query {getTodos(limit: Int, nextToken: String): TodoConnection
}type Todo {id: ID!name: Stringdescription: Stringpriority: Intstatus: TodoStatuscomments: [Comment]
}type TodoConnection {todos: [Todo]nextToken: String
}enum TodoStatus {donepending
}schema {query: Querymutation: Mutation
}

之前我们通过dynamodb生成schema,现在需要使用schema创建对应的dynamodb表

https://docs.amazonaws.cn/appsync/latest/devguide/attaching-a-data-source.html

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

之后需要设置reslover对请求和响应进行映射

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

解析器可以设置为函数或者VTL解析器

  • javascript解析器,用js代码实现的解析器
  • VTL,即 Apache Velocity 模板语言 (VTL)

虽然都不会写,我们使用VTL(看起来简单一些)

详细的解析器教程,https://docs.amazonaws.cn/appsync/latest/devguide/tutorials.html

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

配置模板映射,此处为getTodos的attach

//request
{"version" : "2017-02-28","operation" : "Scan","limit": $util.defaultIfNull(${ctx.args.limit}, 20),"nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.nextToken, null))
}
//response
{"todos": $util.toJson($context.result.items),"nextToken": $util.toJson($context.result.nextToken)
}

为addTodos添加映射

//request
{"version" : "2017-02-28","operation" : "PutItem","key" : {"id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)},"attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
//response
$util.toJson($ctx.result)

在查询中查看结果

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

dynamodb中插入成功

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

从客户端请求

下载schema

$ aws appsync get-introspection-schema --api-id tdmpyyevljaujk4qsreqhp2kvi --format SDL schema.graphql --region cn-north-1

这里我们使用之前创建过的简单demo

$ cat schema.graphql
schema {query: Querymutation: Mutationsubscription: Subscription
}type Mutation {createMyModelType(content: String, title: String!): MyModelTypedeleteMyModelType(id: ID!): MyModelTypeupdateMyModelType(content: String, id: ID!, title: String!): MyModelType
}type MyModelType {content: Stringid: ID!title: String
}type MyModelTypeConnection {items: [MyModelType]nextToken: String
}type Query {getMyModelType(id: ID!): MyModelTypelistMyModelTypes(limit: Int, nextToken: String): MyModelTypeConnection
}type Subscription {onCreateMyModelType(content: String, id: ID, title: String): MyModelType @aws_subscribe(mutations : ["createMyModelType"])onDeleteMyModelType(content: String, id: ID, title: String): MyModelType @aws_subscribe(mutations : ["deleteMyModelType"])onUpdateMyModelType(content: String, id: ID, title: String): MyModelType @aws_subscribe(mutations : ["updateMyModelType"])
}

使用amplify生成项目,选择vue项目,一路默认回车

  • 在src/graphql目录下按照schame生成对应的代码,不需要手写了,每次重新生成即可
$ npx amplify add codegen --apiId tdmpyyevljaujk4qsreqhp2kvi
? Choose the type of app that you're building javascript
? What javascript framework are you using vue
? Choose the code generation language target javascript
? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.js
? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
✔ Generated GraphQL operations successfully and saved at src/graphql// src/graphql/queries.js
export const getMyModelType = /* GraphQL */ `query GetMyModelType($id: ID!) {getMyModelType(id: $id) {contentidtitle}}
`;
export const listMyModelTypes = /* GraphQL */ `query ListMyModelTypes($limit: Int, $nextToken: String) {listMyModelTypes(limit: $limit, nextToken: $nextToken) {items {contentidtitle}nextToken}}
`;

创建认证配置文件

// aws-exports.js
const awsmobile = {
"aws_appsync_graphqlEndpoint": "<API URL>",
"aws_appsync_region": "<REGION>",
"aws_appsync_authenticationType": "API_KEY",
"aws_appsync_apiKey": "<API KEY>",
};export default awsmobile;

项目结构如下

$ tree 
├── schema.graphql
└── src├── aws-exports.js└── graphql├── mutations.js├── queries.js└── subscriptions.js

安装依赖库

npm install @aws-amplify/api

编写客户端

import { API } from '@aws-amplify/api'
import config from './aws-exports.js'
import { listMyModelTypes } from './graphql/queries.js'API.configure(config)async function list() {const response = await API.graphql({// 对应schama中的queryquery: listMyModelTypes,variables: {},})
console.log(JSON.stringify(response))
}
list()

执行获取返回值

$ node src/main.js"
{"data": {"listMyModelTypes": {"items": [{"content": "just for test","id": "ab32729e-4bbf-462f-83f5-74034b68ce9c","title": "test"},{"content": "just for test2","id": "05d23bb5-ba0a-4c32-be77-3782f5da97a2","title": "test2"},{"content": "just for test","id": "7c8de98e-9f88-4bba-844f-f1cfe85d81a2","title": "test"}],"nextToken": null}}
}

测试插入操作

async function add() {const response = await API.graphql({query: createMyModelType,variables: {title: "cli test", content: "just for test cli"},})
console.log(JSON.stringify(response))
}
add()

查看结果

aws appsync 理解和使用appsync为前端应用创建api接口-编程知识网

同样的道理,无论是何种框架,只要接入api就能够使用appsync的接口最数据进行增删改查了