

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 构建 GraphQL API（空白或已导入） APIs
<a name="blank-import-api"></a>

在通过空白模板创建 GraphQL API 之前，回顾一下有关 GraphQL 的概念会有所帮助。GraphQL API 具有三个基本组件：

1. **架构**是包含数据形状和定义的文件。在客户端向您的 GraphQL 服务发出请求时，返回的数据将遵循架构规范。有关更多信息，请参阅 [GraphQL 架构](schema-components.md#aws-appsync-schema-components)。

1. **数据来源**附加到您的架构。在发出请求时，这是检索和修改数据的地方。有关更多信息，请参阅 [数据来源](data-source-components.md#aws-appsync-data-source-components)。

1. **解析器**位于架构和数据来源之间。在发出请求时，解析器对来自数据来源的数据执行操作，然后返回结果以作为响应。有关更多信息，请参阅 [解析器](resolver-components.md#aws-appsync-resolver-components)。

![\[GraphQL API architecture showing schema, resolvers, and data sources connected via AppSync.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/appsync-architecture-graphql-api.png)


AWS AppSync APIs 通过允许您创建、编辑和存储架构和解析器的代码来管理您的。您的数据来源来自外部存储库，例如数据库、DynamoDB 表和 Lambda 函数。如果您正在使用 AWS 服务来存储数据或计划这样做，则在将 AWS 账户中的数据与 GraphQL 关联时，可以 AWS AppSync 提供近乎无缝的体验。 APIs

在下一节中，您将学习如何使用该 AWS AppSync 服务创建每个组件。

**Topics**
+ [设计您的 GraphQL 架构](designing-your-schema.md)
+ [附加数据来源](attaching-a-data-source.md)
+ [配置 AWS AppSync 解析器](resolver-config-overview.md)
+ [APIs 与 CDK 一起使用](using-your-api.md)

# 设计您的 GraphQL 架构
<a name="designing-your-schema"></a>

GraphQL 架构是任何 GraphQL 服务器实施的基础。每个 GraphQL API 由**单个**架构定义，其中包含描述如何填充请求中的数据的类型和字段。必须根据架构验证流经 API 的数据和执行的操作。

一般来说，[GraphQL 类型系统](https://graphql.org/learn/schema/#type-system)描述 GraphQL 服务器的功能，并用于确定查询是否有效。服务器的类型系统通常称为该服务器的架构，可以由不同的对象类型、标量类型、输入类型等组成。GraphQL 既是声明性的，又是强类型的，这意味着将在运行时明确定义类型，并且仅返回指定的内容。

AWS AppSync 允许您定义和配置 GraphQL 架构。以下部分介绍如何使用 AWS AppSync的服务从头开始创建 GraphQL 架构。

## 构建 GraphQL 架构
<a name="schema-structure"></a>

**提示**  
我们建议在继续之前查看[架构](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)一节。

GraphQL 是一种实施 API 服务的强大工具。根据 [GraphQL 网站](https://graphql.org/)，GraphQL 定义如下：

“*GraphQL 是一种查询语言，也是使用现有数据完成这些查询的运行时。 APIs GraphQL 为你的 API 中的数据提供了完整且易于理解的描述，使客户能够准确地询问他们需要什么，仅此而已，使其更容易随着 APIs 时间的推移而发展，并支持强大的开发者工具。* “

本节介绍了 GraphQL 实施的第一部分，即架构。根据上面的引述，架构扮演“为 API 中的数据提供完整且易于理解的描述”角色。换句话说，GraphQL 架构是您的服务的数据、操作以及它们之间的关系的文本表示形式。架构被视为 GraphQL 服务实施的主要入口点。毫不奇怪，它通常是您在项目中首先实施的内容之一。我们建议在继续之前查看[架构](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)一节。

引用[架构](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)一节的内容，GraphQL 架构是使用*架构定义语言* (SDL) 编写的。SDL 由具有既定结构的类型和字段组成：
+ **类型**：类型是 GraphQL 定义数据形状和行为的方式。GraphQL 支持多种类型，本节后面将介绍这些类型。架构中定义的每种类型将包含自己的范围。在该范围内具有一个或多个字段，这些字段可以包含在 GraphQL 服务中使用的值或逻辑。类型扮演很多不同的角色，最常见的角色是对象或标量（基元值类型）。
+ **字段**：字段位于类型范围内，并保存从 GraphQL 服务中请求的值。它们与其他编程语言中的变量非常相似。您在字段中定义的数据形状将决定 request/response 操作中数据的结构方式。这样，开发人员就可以在不知道服务后端实施方式的情况下预测返回的内容。

最简单的架构包含三种不同的数据类别：

1. **架构根**：根定义架构的入口点。它指向对数据执行某种操作（例如添加、删除或修改某些内容）的字段。

1. **类型**：这些是用于表示数据形状的基本类型。您几乎可以将它们视为具有定义的特征的事物的对象或抽象表示形式。例如，您可以创建 `Person` 对象以表示数据库中的某个人。每个人的特征将在 `Person` 中定义为字段。它们可能是这个人的姓名、年龄、工作、地址等任何内容。

1. **特殊对象类型**：这些是在架构中定义操作行为的类型。每种特殊对象类型在每个架构中定义一次。它们先放置在架构根中，然后在架构正文中进行定义。特殊对象类型中的每个字段定义解析器实施的单个操作。

为了便于理解，假设您正在创建一个服务以存储作者及其所写的书籍。每个作者具有姓名和他们撰写的一系列书籍。每本书具有名称和相关的作者列表。我们还希望能够添加或检索书籍和作者。这种关系的简单 UML 表示形式可能如下所示：

![\[UML diagram showing Author and Book classes with attributes and methods, linked by association.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/GraphQL-UML-1.png)


在 GraphQL 中，`Author` 和 `Book` 实体表示架构中的两种不同的对象类型：

```
type Author {
}

type Book {
}
```

`Author` 包含 `authorName` 和 `Books`，而 `Book` 包含 `bookName` 和 `Authors`。这些可以表示为类型范围内的字段：

```
type Author {
  authorName: String
  Books: [Book]
}

type Book {
  bookName: String
  Authors: [Author]
}
```

正如您看到的一样，类型表示形式与图表非常接近。不过，这些方法可能会变得有些复杂。它们将作为字段放置在几种特殊对象类型之一中。它们的特殊对象分类取决于它们的行为。GraphQL 包含三种基本的特殊对象类型：查询、变更和订阅。有关更多信息，请参阅[特殊对象](https://docs.aws.amazon.com//appsync/latest/devguide/graphql-types.html#special-object-components)。

由于 `getAuthor` 和 `getBook` 都请求数据，因此，它们将放置在 `Query` 特殊对象类型中：

```
type Author {
  authorName: String
  Books: [Book]
}

type Book {
  bookName: String
  Authors: [Author]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}
```

这些操作链接到查询，而查询本身链接到架构。添加架构根会将特殊对象类型（该示例中的 `Query`）定义为入口点之一。可以使用 `schema` 关键字完成该操作：

```
schema {
  query: Query
}

type Author {
  authorName: String
  Books: [Book]
}

type Book {
  bookName: String
  Authors: [Author]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}
```

看一下最后两个方法（`addAuthor` 和 `addBook`），它们在数据库中添加数据，因此，它们是在 `Mutation` 特殊对象类型中定义的。不过，从[类型](https://docs.aws.amazon.com/appsync/latest/devguide/graphql-types.html#input-components)页面中，我们还知道不允许直接引用对象的输入，因为它们严格来说是输出类型。在这种情况下，我们不能使用 `Author` 或 `Book`，因此，我们需要创建一种具有相同字段的输入类型。在该示例中，我们添加了 `AuthorInput` 和 `BookInput`，它们接受相应类型的相同字段。然后，我们将输入作为参数以创建变更：

```
schema {
  query: Query
  mutation: Mutation
}

type Author {
  authorName: String
  Books: [Book]
}

input AuthorInput {
  authorName: String
  Books: [BookInput]
}

type Book {
  bookName: String
  Authors: [Author]
}

input BookInput {
  bookName: String
  Authors: [AuthorInput]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}

type Mutation {
  addAuthor(input: [BookInput]): Author
  addBook(input: [AuthorInput]): Book
}
```

让我们回顾一下我们刚刚执行的操作：

1. 我们创建了一个具有 `Book` 和 `Author` 类型的架构以表示我们的实体。

1. 我们添加了包含实体特性的字段。

1. 我们添加了一个查询，以从数据库中检索该信息。

1. 我们添加了一个变更以处理数据库中的数据。

1. 我们添加了输入类型以在变更中替换对象参数，从而符合 GraphQL 的规则。

1. 我们将查询和变更添加到根架构中，以使 GraphQL 实施了解根类型位置。

正如您看到的一样，创建架构的过程通常采用数据建模（尤其是数据库建模）中的一些概念。您可以将架构视为适合源数据的形状。它还充当解析器实施的模型。在以下各节中，您将学习如何使用各种 AWS支持的工具和服务来创建架构。

**注意**  
以下几节中的示例并不表示在实际应用程序中运行。它们仅用于说明这些命令，以使您可以构建自己的应用程序。

## 创建架构
<a name="creating-schema"></a>

您的架构将位于名为的文件中`schema.graphql`。 AWS AppSync 允许用户使用各种方法为其 G APIs raphQL 创建新的架构。在该示例中，我们将创建一个空白 API 以及空白架构。

------
#### [ Console ]

1. 登录 AWS 管理控制台 并打开[AppSync控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**控制面板**中，选择**创建 API**。

   1. **在 **API 选项下，选择** **GraphQL APIs**、**从头开始设计**，然后选择 “下一步”。**

      1. 对于 **API 名称**，将预填充的名称更改为您的应用程序所需的名称。

      1. 对于**联系信息**，您可以输入联系人以指定 API 的管理员。此为可选字段。

      1. 在**私有 API 配置**下面，您可以启用私有 API 功能。只能从配置的 VPC 终端节点 (VPCE) 中访问私有 API。有关更多信息，请参阅[私有 APIs](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html)。

         对于该示例，我们不建议启用该功能。在检查您的输入后，选择**下一步**。

   1. 在**创建 GraphQL 类型**下面，您可以选择创建 DynamoDB 表以用作数据来源，或者跳过该步骤并稍后执行。

      对于该示例，请选择**稍后创建 GraphQL 资源**。我们将在单独的章节中创建资源。

   1. 检查您的输入，然后选择**创建 API**。

1. 将进入您的特定 API 的控制面板。由于该 API 的名称位于控制面板顶部，因此，您可以看出这一点。如果不是这样，你可以在**侧栏**APIs****中选择，然后在**APIs 控制面板**中选择你的 API。

   1. 在**侧边栏**中，在您的 API 名称下面选择**架构**。

1. 在**架构编辑器**中，您可以配置您的 `schema.graphql` 文件。它可能是空的，也可能填充了通过模型生成的类型。右侧是**解析器**部分，用于将解析器附加到您的架构字段。我们不会在本节中介绍解析器内容。

------
#### [ CLI ]

**注意**  
在使用 CLI 时，请确保您具有正确权限以在该服务中访问和创建资源。您可能希望为需要访问该服务的非管理员用户设置[最低权限](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege)策略。有关 AWS AppSync 策略的更多信息，请参阅的[身份和访问管理 AWS AppSync](https://docs.aws.amazon.com//appsync/latest/devguide/security-iam.html)。  
此外，如果您还没有查看控制台版本，我们建议您先查看该版本。

1. 如果您尚未[安装](https://docs.aws.amazon.com//cli/latest/userguide/cli-chap-getting-started.html) AWS CLI 并添加您的[配置](https://docs.aws.amazon.com//cli/latest/userguide/cli-configure-quickstart.html)，请执行该操作。

1. 运行 [https://docs.aws.amazon.com/cli/latest/reference/appsync/create-graphql-api.html](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-graphql-api.html) 命令以创建 GraphQL API 对象。

   您需要为该特定命令键入两个参数：

   1. 您的 API 的 `name`。

   1. `authentication-type` 或用于访问该 API 的凭证类型（IAM、OIDC 等）。
**注意**  
必须配置其他参数（例如 `Region`），但这些参数通常默认为您的 CLI 配置值。

   示例命令可能如下所示：

   ```
   aws appsync create-graphql-api --name testAPI123 --authentication-type API_KEY
   ```

   将在 CLI 中返回输出。示例如下：

   ```
   {
       "graphqlApi": {
           "xrayEnabled": false,
           "name": "testAPI123",
           "authenticationType": "API_KEY",
           "tags": {},
           "apiId": "abcdefghijklmnopqrstuvwxyz",
           "uris": {
               "GRAPHQL": "https://zyxwvutsrqponmlkjihgfedcba.appsync-api.us-west-2.amazonaws.com/graphql",
               "REALTIME": "wss://zyxwvutsrqponmlkjihgfedcba.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
           },
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz"
       }
   }
   ```

1. 
**注意**  
这是一个可选命令，它采用现有的架构并使用 Base64 Blob 将其上传到 AWS AppSync 服务中。对于该示例，我们不会使用该命令。

   运行 [https://docs.aws.amazon.com/cli/latest/reference/appsync/start-schema-creation.html](https://docs.aws.amazon.com/cli/latest/reference/appsync/start-schema-creation.html) 命令。

   您需要为该特定命令键入两个参数：

   1. 上一步中的 `api-id`。

   1. 架构 `definition` 是一个 Base64 编码的二进制 Blob。

   示例命令可能如下所示：

   ```
    aws appsync start-schema-creation --api-id abcdefghijklmnopqrstuvwxyz --definition "aa1111aa-123b-2bb2-c321-12hgg76cc33v"
   ```

   将返回输出：

   ```
   {
       "status": "PROCESSING"
   }
   ```

   该命令不会在处理后返回最终输出。您必须使用单独的命令 ([https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/get-schema-creation-status.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/get-schema-creation-status.html)) 查看结果。请注意，这两个命令是异步的，因此，即使仍在创建架构，您也可以检查输出状态。

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我们建议您查看 CDK 的[官方文档](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 [CD](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 AWS AppSync  
下面列出的步骤仅显示用于添加特定资源的一般代码片段示例。这**并不**意味着，它是您的生产代码中的有效解决方案。我们还假设您已具有正常工作的应用程序。

1. CDK 的起点有所不同。理想情况下，应该已创建了您的 `schema.graphql` 文件。您只需创建一个具有 `.graphql` 文件扩展名的新文件。它可以是空文件。

1. 一般来说，您可能需要将 import 指令添加到您使用的服务中。例如，它可能采用以下形式：

   ```
   import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
   import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
   ```

   要添加 GraphQL API，您的堆栈文件需要导入 AWS AppSync 服务：

   ```
   import * as appsync from 'aws-cdk-lib/aws-appsync';
   ```
**注意**  
这意味着我们使用 `appsync` 关键字导入整个服务。要在您的应用程序中使用它，您的 AWS AppSync 构造将使用以下格式`appsync.construct_name`。例如，如果我们要创建 GraphQL API，我们将使用 `new appsync.GraphqlApi(args_go_here)`。以下步骤介绍了这一点。

1. 最基本的 GraphQL API 将包括 API 的 `name` 和 `schema` 路径。

   ```
   const add_api = new appsync.GraphqlApi(this, 'API_ID', {
     name: 'name_of_API_in_console',
     schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'schema_name.graphql')),
   });
   ```
**注意**  
让我们回顾一下该代码片段执行的操作。在 `api` 范围内，我们调用 `appsync.GraphqlApi(scope: Construct, id: string, props: GraphqlApiProps)` 以创建一个新的 GraphQL API。范围是 `this`，它指的是当前对象。ID 是*API\$1ID*，这将是你的 GraphQL API 在创建 CloudFormation 时使用的资源名称。`GraphqlApiProps` 包含 GraphQL API 的 `name` 和 `schema`。`schema`将通过在绝对路径 (`SchemaFile.fromAsset`) 中搜索`.graphql`文件 (`__dirname`) 来生成架构 (*schema\$1name.graphql*)。在实际场景中，您的架构文件可能位于 CDK 应用程序内。  
要使用对 GraphQL API 所做的更改，您必须重新部署该应用程序。

------

## 在架构中添加类型
<a name="adding-schema-types"></a>

现已添加了架构，您可以开始添加输入和输出类型。请注意，不应在实际代码中使用此处的类型；它们只是帮助您理解该过程的示例。

首先，我们创建一个对象类型。在实际代码中，您不必从这些类型开始。只要遵循 GraphQL 的规则和语法，您可以随时创建所需的任何类型。

**注意**  
接下来的几节将使用**架构编辑器**，因此，请将其保持打开状态。

------
#### [ Console ]
+ 您可以使用 `type` 关键字和类型名称以创建对象类型：

  ```
  type Type_Name_Goes_Here {}
  ```

  在类型的范围内，您可以添加表示对象特性的字段：

  ```
  type Type_Name_Goes_Here {
    # Add fields here
  }
  ```

  示例如下：

  ```
  type Obj_Type_1 {
    id: ID!
    title: String
    date: AWSDateTime
  }
  ```
**注意**  
在该骤中，我们添加了一个通用对象类型，将 `id` 必填字段存储为 `ID`，将 `title` 字段存储为 `String`，并将 `date` 字段存储为 `AWSDateTime`。要查看类型和字段列表及其用途，请参阅[架构](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)。要查看标量列表及其用途，请参阅[类型参考](https://docs.aws.amazon.com/appsync/latest/devguide/type-reference.html)。

------
#### [ CLI ]

**注意**  
如果您还没有查看控制台版本，我们建议您先查看该版本。
+ 您可以运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html) 命令以创建对象类型。

  您需要为该特定命令输入一些参数：

  1. 您的 API 的 `api-id`。

  1. `definition` 或您的类型内容。在控制台示例中，这是：

     ```
     type Obj_Type_1 {
       id: ID!
       title: String
       date: AWSDateTime
     }
     ```

  1. 您的输入的 `format`。在该示例中，我们使用 `SDL`。

  示例命令可能如下所示：

  ```
  aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "type Obj_Type_1{id: ID! title: String date: AWSDateTime}" --format SDL
  ```

  将在 CLI 中返回输出。示例如下：

  ```
  {
      "type": {
          "definition": "type Obj_Type_1{id: ID! title: String date: AWSDateTime}",
          "name": "Obj_Type_1",
          "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Obj_Type_1",
          "format": "SDL"
      }
  }
  ```
**注意**  
在该骤中，我们添加了一个通用对象类型，将 `id` 必填字段存储为 `ID`，将 `title` 字段存储为 `String`，并将 `date` 字段存储为 `AWSDateTime`。要查看类型和字段列表及其用途，请参阅[架构](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)。要查看标量列表及其用途，请参阅[类型参考](https://docs.aws.amazon.com/appsync/latest/devguide/type-reference.html)。  
此外，您可能已意识到，直接输入定义适用于较小的类型，但对于添加较大类型或多个类型是不可行的。您可以选择将所有内容添加到 `.graphql` 文件中，然后[将其作为输入传递](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-file.html)。

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我们建议您查看 CDK 的[官方文档](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 [CD](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 AWS AppSync  
下面列出的步骤仅显示用于添加特定资源的一般代码片段示例。这**并不**意味着，它是您的生产代码中的有效解决方案。我们还假设您已具有正常工作的应用程序。

要添加类型，您需要将其添加到您的 `.graphql` 文件中。例如，控制台示例是：

```
type Obj_Type_1 {
  id: ID!
  title: String
  date: AWSDateTime
}
```

您可以像任何其他文件一样将类型直接添加到架构中。

**注意**  
要使用对 GraphQL API 所做的更改，您必须重新部署该应用程序。

------

[对象类型](https://graphql.org/learn/schema/#object-types-and-fields)具有[标量类型的](https://graphql.org/learn/schema/#scalar-types)字段，例如字符串和整数。 AWS AppSync 除基本的 GraphQL 标量外，还允许您使用增强的标量类型。`AWSDateTime`此外，任何以感叹号结尾的字段都是必填字段。

特别是，`ID` 标量类型是唯一标识符，可以是 `String` 或 `Int`。您可以在解析器代码中控制这些内容以自动进行分配。

特殊对象类型（如 `Query`）和“常规”对象类型（如上面的示例）之间存在相似之处，因为它们都使用 `type` 关键字并被视为对象。不过，对于特殊对象类型（`Query`、`Mutation` 和 `Subscription`），它们的行为有很大不同，因为它们是作为 API 的入口点公开的。它们更多地涉及设置形状操作而不是数据。有关更多信息，请参阅[查询和变更类型](https://graphql.org/learn/schema/#the-query-and-mutation-types)。

对于特殊对象类型主题，下一步可能是添加一个或多个对象类型以对设置形状的数据执行操作。在实际场景中，每个 GraphQL 架构必须至少具有一个根查询类型以请求数据。您可以将查询视为 GraphQL 服务器的入口点（或终端节点）之一。让我们添加一个查询以作为示例。

------
#### [ Console ]
+ 要创建查询，您只需将其添加到架构文件中，就像任何其他类型一样。查询需要具有 `Query` 类型并在根中具有一个条目，如下所示：

  ```
  schema {
    query: Name_of_Query
  }
  
  type Name_of_Query {
    # Add field operation here
  }
  ```

  请注意，*Name\$1of\$1Query*在生产环境中，大多数`Query`情况下只会被调用。我们建议保留该值。在查询类型中，您可以添加字段。每个字段都会在请求中执行一个操作。因此，大多数（即使不是全部）字段将附加到一个解析器。不过，我们在本节中并不关注这个问题。对于字段操作格式，它可能如下所示：

  ```
  Name_of_Query(params): Return_Type # version with params
  Name_of_Query: Return_Type # version without params
  ```

  示例如下：

  ```
  schema {
    query: Query
  }
  
  type Query {
    getObj: [Obj_Type_1]
  }
  
  type Obj_Type_1 {
    id: ID!
    title: String
    date: AWSDateTime
  }
  ```
**注意**  
在该步骤中，我们添加了一个 `Query` 类型，并在 `schema` 根中定义该类型。我们的 `Query` 类型定义了一个 `getObj` 字段，该字段返回 `Obj_Type_1` 对象列表。请注意，`Obj_Type_1` 是上一步中的对象。在生产代码中，您的字段操作通常处理由 `Obj_Type_1` 等对象设置形状的数据。此外，`getObj` 等字段通常具有一个解析器以执行业务逻辑。将在另一节中介绍该内容。  
另外，在导出过程中 AWS AppSync 会自动添加架构根，因此从技术上讲，您不必将其直接添加到架构中。我们的服务自动处理重复的架构。我们在此处添加架构根以作为最佳实践。

------
#### [ CLI ]

**注意**  
如果您还没有查看控制台版本，我们建议您先查看该版本。

1. 运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html) 命令以创建一个具有 `query` 定义的 `schema` 根。

   您需要为该特定命令输入一些参数：

   1. 您的 API 的 `api-id`。

   1. `definition` 或您的类型内容。在控制台示例中，这是：

      ```
      schema {
        query: Query
      }
      ```

   1. 您的输入的 `format`。在该示例中，我们使用 `SDL`。

   示例命令可能如下所示：

   ```
   aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "schema {query: Query}" --format SDL
   ```

   将在 CLI 中返回输出。示例如下：

   ```
   {
       "type": {
           "definition": "schema {query: Query}",
           "name": "schema",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/schema",
           "format": "SDL"
       }
   }
   ```
**注意**  
请注意，如果您在 `create-type` 命令中未正确输入某些内容，您可以运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html) 命令以更新您的架构根（或架构中的任何类型）。在该示例中，我们暂时更改架构根以包含 `subscription` 定义。  
您需要为该特定命令输入一些参数：  
您的 API 的 `api-id`。
您的类型的 `type-name`。在控制台示例中，这是 `schema`。
`definition` 或您的类型内容。在控制台示例中，这是：  

      ```
      schema {
        query: Query
      }
      ```
添加 `subscription` 后的架构如下所示：  

      ```
      schema {
        query: Query
        subscription: Subscription
      }
      ```
您的输入的 `format`。在该示例中，我们使用 `SDL`。
示例命令可能如下所示：  

   ```
   aws appsync update-type --api-id abcdefghijklmnopqrstuvwxyz --type-name schema --definition "schema {query: Query subscription: Subscription}" --format SDL
   ```
将在 CLI 中返回输出。示例如下：  

   ```
   {
       "type": {
           "definition": "schema {query: Query subscription: Subscription}",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/schema",
           "format": "SDL"
       }
   }
   ```
在该示例中，添加预设置格式的文件仍然有效。

1. 运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html) 命令以创建一个 `Query` 类型。

   您需要为该特定命令输入一些参数：

   1. 您的 API 的 `api-id`。

   1. `definition` 或您的类型内容。在控制台示例中，这是：

      ```
      type Query {
        getObj: [Obj_Type_1]
      }
      ```

   1. 您的输入的 `format`。在该示例中，我们使用 `SDL`。

   示例命令可能如下所示：

   ```
   aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "type Query {getObj: [Obj_Type_1]}" --format SDL
   ```

   将在 CLI 中返回输出。示例如下：

   ```
   {
       "type": {
           "definition": "Query {getObj: [Obj_Type_1]}",
           "name": "Query",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Query",
           "format": "SDL"
       }
   }
   ```
**注意**  
在该步骤中，我们添加了一个 `Query` 类型，并在 `schema` 根中定义该类型。我们的 `Query` 类型定义了一个 `getObj` 字段，该字段返回 `Obj_Type_1` 对象列表。  
在 `schema` 根代码 `query: Query` 中，`query:` 部分指示在您的架构中定义了一个查询，而 `Query` 部分指示实际的特殊对象名称。

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我们建议您查看 CDK 的[官方文档](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 [CD](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 AWS AppSync  
下面列出的步骤仅显示用于添加特定资源的一般代码片段示例。这**并不**意味着，它是您的生产代码中的有效解决方案。我们还假设您已具有正常工作的应用程序。

您需要将查询和架构根添加到 `.graphql` 文件中。我们的示例与以下示例类似，但您希望将其替换为实际的架构代码：

```
schema {
  query: Query
}

type Query {
  getObj: [Obj_Type_1]
}

type Obj_Type_1 {
  id: ID!
  title: String
  date: AWSDateTime
}
```

您可以像任何其他文件一样将类型直接添加到架构中。

**注意**  
更新架构根是可选的。我们在该示例中添加架构根以作为最佳实践。  
要使用对 GraphQL API 所做的更改，您必须重新部署该应用程序。

------

您现已看到创建对象和特殊对象（查询）的示例。您还了解了这些对象如何相互关联以描述数据和操作。您可以具有仅包含数据描述以及一个或多个查询的架构。不过，我们希望添加另一个操作以将数据添加到数据来源中。我们将添加另一个名为 `Mutation` 的特殊对象类型以修改数据。

------
#### [ Console ]
+ 一个变更命名为 `Mutation`。与 `Query` 一样，`Mutation` 中的字段操作描述一个操作并附加到一个解析器。另请注意，我们需要在 `schema` 根中定义该变更，因为它是一个特殊对象类型。下面是一个变更示例：

  ```
  schema {
    mutation: Name_of_Mutation
  }
  
  type Name_of_Mutation {
    # Add field operation here
  }
  ```

  像查询一样，将在根中列出典型的变更。变异是使用`type`关键字和名称定义的。 *Name\$1of\$1Mutation*通常会被调用`Mutation`，所以我们建议保持这种状态。每个字段还会执行一个操作。对于字段操作格式，它可能如下所示：

  ```
  Name_of_Mutation(params): Return_Type # version with params
  Name_of_Mutation: Return_Type # version without params
  ```

  示例如下：

  ```
  schema {
    query: Query
    mutation: Mutation
  }
  
  type Obj_Type_1 {
    id: ID!
    title: String
    date: AWSDateTime
  }
  
  type Query {
    getObj: [Obj_Type_1]
  }
  
  type Mutation {
    addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
  }
  ```
**注意**  
在该步骤中，我们添加了一个具有 `addObj` 字段的 `Mutation` 类型。让我们简要说明一下该字段的用途：  

  ```
  addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
  ```
`addObj` 使用 `Obj_Type_1` 对象以执行操作。由于这些字段，这是显而易见的，但语法在 `: Obj_Type_1` 返回类型中证实了这一点。在 `addObj` 中，它接受 `Obj_Type_1` 对象中的 `id`、`title` 和 `date` 字段以作为参数。正如您看到的一样，它看起来很像方法声明。不过，我们还没有介绍我们的方法的行为。正如前面所述，架构仅用于定义数据和操作是什么，而不定义它们的工作方式。在我们稍后创建第一个解析器时，将实施实际的业务逻辑。  
在完成架构后，可以选择将其导出为 `schema.graphql` 文件。在**架构编辑器**中，您可以选择**导出架构**以使用支持的格式下载该文件。  
另外，在导出过程中 AWS AppSync 会自动添加架构根，因此从技术上讲，您不必将其直接添加到架构中。我们的服务自动处理重复的架构。我们在此处添加架构根以作为最佳实践。

------
#### [ CLI ]

**注意**  
如果您还没有查看控制台版本，我们建议您先查看该版本。

1. 运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html) 命令以更新您的根架构。

   您需要为该特定命令输入一些参数：

   1. 您的 API 的 `api-id`。

   1. 您的类型的 `type-name`。在控制台示例中，这是 `schema`。

   1. `definition` 或您的类型内容。在控制台示例中，这是：

      ```
      schema {
        query: Query
        mutation: Mutation
      }
      ```

   1. 您的输入的 `format`。在该示例中，我们使用 `SDL`。

   示例命令可能如下所示：

   ```
   aws appsync update-type --api-id abcdefghijklmnopqrstuvwxyz --type-name schema --definition "schema {query: Query mutation: Mutation}" --format SDL
   ```

   将在 CLI 中返回输出。示例如下：

   ```
   {
       "type": {
           "definition": "schema {query: Query mutation: Mutation}",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/schema",
           "format": "SDL"
       }
   }
   ```

1. 运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html) 命令以创建一个 `Mutation` 类型。

   您需要为该特定命令输入一些参数：

   1. 您的 API 的 `api-id`。

   1. `definition` 或您的类型内容。在控制台示例中，这是：

      ```
      type Mutation {
        addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
      }
      ```

   1. 您的输入的 `format`。在该示例中，我们使用 `SDL`。

   示例命令可能如下所示：

   ```
   aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "type Mutation {addObj(id: ID! title: String date: AWSDateTime): Obj_Type_1}" --format SDL
   ```

   将在 CLI 中返回输出。示例如下：

   ```
   {
       "type": {
           "definition": "type Mutation {addObj(id: ID! title: String date: AWSDateTime): Obj_Type_1}",
           "name": "Mutation",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation",
           "format": "SDL"
       }
   }
   ```

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我们建议您查看 CDK 的[官方文档](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 [CD](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 AWS AppSync  
下面列出的步骤仅显示用于添加特定资源的一般代码片段示例。这**并不**意味着，它是您的生产代码中的有效解决方案。我们还假设您已具有正常工作的应用程序。

您需要将查询和架构根添加到 `.graphql` 文件中。我们的示例与以下示例类似，但您希望将其替换为实际的架构代码：

```
schema {
  query: Query
  mutation: Mutation
}

type Obj_Type_1 {
  id: ID!
  title: String
  date: AWSDateTime
}

type Query {
  getObj: [Obj_Type_1]
}

type Mutation {
  addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
}
```

**注意**  
更新架构根是可选的。我们在该示例中添加架构根以作为最佳实践。  
要使用对 GraphQL API 所做的更改，您必须重新部署该应用程序。

------

## 可选注意事项 - 将枚举作为状态
<a name="optional-consideration-enums"></a>

至此，您知道如何创建基本架构了。不过，您可以添加很多内容以增加架构的功能。在应用程序中，一种常见情况是将枚举作为状态。您可以使用枚举在调用时强制从一组值中选择一个特定的值。对于您知道在很长一段时间内不会发生显著变化的内容，这是非常有用的。假设来说，我们可以添加一个枚举以在响应中返回状态代码或字符串。

例如，假设我们创建一个社交媒体应用程序，该应用程序在后端存储用户的文章数据。我们的架构包含一个 `Post` 类型，它表示一篇文章的数据：

```
type Post {
  id: ID!
  title: String
  date: AWSDateTime
  poststatus: PostStatus
}
```

我们的 `Post` 将包含唯一的 `id`、文章 `title`、发布 `date` 以及名为 `PostStatus` 的枚举，它表示应用程序处理时的文章状态。对于我们的操作，我们使用一个查询以返回所有文章数据：

```
type Query {
  getPosts: [Post]
}
```

我们还使用一个变更以将文章添加到数据来源中：

```
type Mutation {
  addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}
```

看一下我们的架构，`PostStatus` 枚举可能具有多种状态。我们可能需要三种基本状态，分别命名为 `success`（已成功处理文章）、`pending`（正在处理文章）和 `error`（无法处理文章）。要添加枚举，我们可以编写以下代码：

```
enum PostStatus {
  success
  pending
  error
}
```

完整架构可能如下所示：

```
schema {
  query: Query
  mutation: Mutation
}

type Post {
  id: ID!
  title: String
  date: AWSDateTime
  poststatus: PostStatus
}

type Mutation {
  addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}

type Query {
  getPosts: [Post]
}

enum PostStatus {  
  success
  pending
  error
}
```

如果用户在应用程序中添加 `Post`，将调用 `addPost` 操作以处理该数据。在附加到 `addPost` 的解析器处理数据时，它不断使用操作状态更新 `poststatus`。在查询时，`Post` 将包含数据的最终状态。请记住，我们只是介绍我们希望如何在架构中处理数据。我们对解析器实施进行了很多假设，这些解析器实施处理数据以完成请求的实际业务逻辑。

## 可选注意事项 - 订阅
<a name="optional-consideration-subscriptions"></a>

中的订阅 AWS AppSync 是作为对突变的响应而调用的。您可使用架构中的`Subscription` 类型和 `@aws_subscribe()` 指令进行配置，以指定哪些变更会调用一个或多个订阅。有关配置订阅的更多信息，请参阅[实时数据](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html)。

## 可选的注意事项 - 关系和分页
<a name="optional-consideration-relations-and-pagination"></a>

假设您在 DynamoDB 表中存储了一百万个 `Posts`，并且您希望返回其中的一些数据。不过，上面给出的示例查询仅返回所有文章。您不希望每次发出请求时获取所有这些文章。相反，您可能希望对它们进行[分页](https://graphql.org/learn/pagination/)。请对您的架构进行以下改动：
+ 在 `getPosts` 字段中，添加两个输入参数：`nextToken`（迭代器）和 `limit`（迭代限制）。
+ 添加一个新的 `PostIterator` 类型，其中包含 `Posts`（检索 `Post` 对象列表）和 `nextToken`（迭代器）字段。
+ 更改 `getPosts` 以使其返回 `PostIterator`，而不是 `Post` 对象列表。

```
schema {
  query: Query
  mutation: Mutation
}

type Post {
  id: ID!
  title: String
  date: AWSDateTime
  poststatus: PostStatus
}

type Mutation {
  addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}

type Query {
  getPosts(limit: Int, nextToken: String): PostIterator
}

enum PostStatus {
  success
  pending
  error
}

type PostIterator {
  posts: [Post]
  nextToken: String
}
```

`PostIterator` 类型允许您返回 `Post` 对象列表的一部分，以及用于获取下一部分的 `nextToken`。在 `PostIterator` 中，具有一个 `Post` 项目 (`[Post]`) 列表，该列表与分页标记 (`nextToken`) 一起返回。在中 AWS AppSync，它将通过解析器连接到 Amazon DynamoDB，并自动生成为加密令牌。它会将 `limit` 参数的值转换为 `maxResults` 参数；并将 `nextToken` 参数转换为 `exclusiveStartKey` 参数。有关 AWS AppSync 控制台中的示例和内置模板示例，请参阅 [Resolver 参考 (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html)。

# 将数据源附加到 AWS AppSync
<a name="attaching-a-data-source"></a>

数据源是 GraphQL APIs 可以与之交互的 AWS 账户中的资源。 AWS AppSync 支持多种数据源 AWS Lambda，例如亚马逊 DynamoDB、关系数据库（亚马逊 Aurora Serverless）、 OpenSearch 亚马逊服务和 HTTP 终端节点。可以将 AWS AppSync API 配置为与多个数据源进行交互，从而使您能够将数据聚合到一个位置。 AWS AppSync 可以使用您账户中的现有 AWS 资源或代表您通过架构定义配置 DynamoDB 表。

以下几节说明了如何将数据来源附加到 GraphQL API。

## 数据来源类型
<a name="data-source-types"></a>

现在，您已经在 AWS AppSync 控制台中创建了架构，可以将数据源附加到该架构。在您最初创建 API 时，可以选择在创建预定义的架构期间预置 Amazon DynamoDB 表。不过，我们不会在本节中介绍该选项。您可以在[启动架构](https://docs.aws.amazon.com//appsync/latest/devguide/schema-launch-start.html)一节中查看该选项的示例。

相反，我们将研究所有 AWS AppSync 支持的数据源。在为您的应用程序选择正确的解决方案时，需要考虑很多因素。以下几节为每个数据来源提供一些额外的上下文。有关数据来源的一般信息，请参阅[数据来源](https://docs.aws.amazon.com/appsync/latest/devguide/data-source-components.html)。

### Amazon DynamoDB
<a name="data-source-type-ddb"></a>

Amazon DynamoDB 是可扩展应用程序的 “主要” 存储解决方案之一 AWS。DynamoDB 的核心组件是**表**，它就是一个数据集合。您通常会根据 `Book` 或 `Author` 等实体创建表。表条目信息存储为**项目**，这些项目是每个条目的唯一字段组。完整的项目表示数据库 row/record 中的。例如，`Book` 条目的项目可能包括 `title` 和 `author` 及其值。像 `title` 和 `author` 这样的单独字段称为**属性**，它们类似于关系数据库中的列值。

你可以猜到，表将用于存储应用程序中的数据。 AWS AppSync 允许你将 DynamoDB 表连接到 GraphQL API 来操作数据。请从*前端 Web 和移动博客*中获取该[使用案例](https://aws.amazon.com/blogs/mobile/new-real-time-multi-group-app-with-aws-amplify-graphql-build-a-twitter-community-clone/)。该应用程序允许用户注册社交媒体应用程序。用户可以加入组，并上传文章以向订阅该组的其他用户广播。他们的应用程序将用户、文章和用户组信息存储在 DynamoDB 中。GraphQL API（由管理 AWS AppSync）与 DynamoDB 表连接。当用户在系统中进行更改并反映到前端时，GraphQL API 检索这些更改并向其他用户实时广播。

### AWS Lambda
<a name="data-source-type-lam"></a>

Lambda 是一种事件驱动的服务，它自动构建所需的资源以运行代码，从而响应事件。Lambda 使用**函数**，这些函数是包含用于执行资源的代码、依赖项和配置的组语句。在函数检测到**触发器**（一组调用函数的活动）时，将自动执行函数。触发器可以是应用程序发出 API 调用、账户中的 AWS 服务启动资源等。在触发时，函数将处理**事件**，这些事件是包含要修改的数据的 JSON 文档。

Lambda 非常适合运行代码，无需预置资源即可运行。请从*前端 Web 和移动博客*中获取该[使用案例](https://aws.amazon.com/blogs/mobile/building-a-graphql-api-with-java-and-aws-lambda/)。该使用案例与 DynamoDB 一节中说明的使用案例有点相似。在该应用程序中，GraphQL API 负责定义操作，例如，添加文章（变更）和获取该数据（查询）。为了实施其操作的功能（例如 `getPost ( id: String ! ) : Post`、`getPostsByAuthor ( author: String ! ) : [ Post ]`），它们使用 Lambda 函数处理入站请求。根据*选项 2： AWS AppSync 使用 Lambda 解析器*，他们使用该 AWS AppSync 服务来维护自己的架构，并将 Lambda 数据源链接到其中一个操作。在调用该操作时，Lambda 与 Amazon RDS 代理交互以对数据库执行业务逻辑。

### Amazon RDS
<a name="data-source-type-RDS"></a>

通过使用 Amazon RDS，您可以快速构建和配置关系数据库。在 Amazon RDS 中，您将创建一个通用**数据库实例**，以作为云中的隔离数据库环境。在该示例中，您使用一个**数据库引擎**，它是实际的 RDBMS 软件（PostgreSQL、MySQL 等）。该服务使用 AWS“基础架构”、修补和加密等安全服务提供可扩展性，从而减轻了大部分后端工作，并降低了部署的管理成本。

使用 Lambda 一节中的相同[使用案例](https://aws.amazon.com/blogs/mobile/building-a-graphql-api-with-java-and-aws-lambda/)。在*选项 3： AWS AppSync 使用亚马逊 RDS 解析器*下，提供的另一个选项是将 GraphQL API 直接链接 AWS AppSync 到亚马逊 RDS。通过使用[数据 API](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html)，他们将数据库与 GraphQL API 相关联。一个解析器附加到字段（通常是查询、变更或订阅），并实施访问数据库所需的 SQL 语句。在客户端发出调用该字段的请求时，解析器执行这些语句并返回响应。

### Amazon EventBridge
<a name="data-source-type-eventbridge"></a>

在中 EventBridge，您将创建**事件总线**，这些管道接收来自您附加的服务或应用程序（**事件源**）的事件，并根据一组规则对其进行处理。**事件**是执行环境中的某种状态变化，而**规则**是事件的一组筛选条件。规则遵循一种**事件模式**或事件状态变化元数据（ID、区域、账号、ARN 等）。当事件与事件模式匹配时， EventBridge 将通过管道将事件发送到**目标服务（目标**），并触发规则中指定的操作。

EventBridge 非常适合将状态更改操作路由到其他服务。请从*前端 Web 和移动博客*中获取该[使用案例](https://aws.amazon.com/blogs/mobile/appsync-eventbridge/)。该示例介绍了一个电子商务解决方案，该解决方案具有多个团队以维护不同的服务。其中的一种服务在前端针对每个交付步骤（下订单、处理中、发货、交付等）向客户提供订单更新。不过，管理该服务的前端团队无法直接访问订购系统数据，因为该数据是由单独的后端团队维护的。后端团队的订购系统也被描述为黑匣子，因此，很难收集有关他们如何设置数据结构的信息。但是，后端团队确实建立了一个系统，该系统通过由管理的事件总线发布订单数据 EventBridge。为了访问来自事件总线的数据并将其路由到前端，前端团队创建了一个指向其GraphQL API的新目标。 AWS AppSync他们还创建一条规则，以仅发送与订单更新相关的数据。在进行更新时，来自该事件总线的数据将发送到 GraphQL API。API 中的架构处理数据，然后将其传送到前端。

### None 数据来源
<a name="data-source-type-none"></a>

如果不打算使用数据来源，您可以将其设置为 `none`。虽然 `none` 数据来源仍明确归类为数据来源，但并不是存储介质。通常，解析器在某一时刻调用一个或多个数据来源以处理请求。不过，在某些情况下，您可能不需要处理数据来源。如果将数据来源设置为 `none`，将运行请求，跳过数据调用步骤，然后运行响应。

从本 EventBridge 节中取同样的[用例](https://aws.amazon.com/blogs/mobile/appsync-eventbridge/)。在架构中，变更处理状态更新，然后将其发送给订阅者。回想一下解析器的工作方式，通常至少调用一次数据来源。不过，事件总线已自动发送本场景中的数据。这意味着变更不需要执行数据来源调用；可以直接在本地处理订单状态。变更设置为 `none`，它充当传递值而不会调用数据来源。然后，使用数据填充架构，该数据将发送给订阅者。

### OpenSearch
<a name="data-source-type-opensearch"></a>

Amazon S OpenSearch ervice 是一套用于实现全文搜索、数据可视化和日志记录的工具。可以使用该服务查询您上传的结构化数据。

在此服务中，您将创建的实例 OpenSearch。这些实例称为**节点**。在节点中，您添加至少一个**索引**。从概念上讲，索引有点像关系数据库中的表。（但是， OpenSearch 不符合 ACID，因此不应以这种方式使用）。您将使用上传到 OpenSearch 服务的数据填充索引。在上传您的数据时，将使用索引中存在的一个或多个分片对其编制索引。**分片**就像索引的一个分区，其中包含一些数据，并且可以与其他分片分开查询。在上传后，您的数据结构设置为称为**文档**的 JSON 文件。然后，您可以查询节点以获取文档中的数据。

### HTTP 端点
<a name="data-source-type-http"></a>

您可以使用 HTTP 端点作为数据源。 AWS AppSync 可以向端点发送包含参数和有效载荷等相关信息的请求。将向解析器公开 HTTP 响应，解析器在完成操作后返回最终响应。

## 添加数据来源
<a name="adding-a-data-source"></a>

如果您创建了数据源，则可以将其链接到 AWS AppSync 服务，更具体地说，可以链接到 API。

------
#### [ Console ]

1. 登录 AWS 管理控制台 并打开[AppSync控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**控制面板**中选择您的 API。

   1. 在**侧边栏**中，选择**数据来源**。

1. 选择**创建数据来源**。

   1. 命名您的数据来源。您也可以为其提供描述，但这是可选的。

   1. 选择您的**数据来源类型**。

   1. 对于 DynamoDB，必须选择您的区域，然后选择该区域中的表。您可以选择创建新的通用表角色或导入表的现有角色，以规定与表交互的规则。您可以启用[版本控制](https://docs.aws.amazon.com/appsync/latest/devguide/conflict-detection-and-sync.html)，在多个客户端同时尝试更新数据时，该功能可以自动为每个请求创建数据版本。版本控制用于保留和维护多个数据变体，以实现冲突检测和解决目的。您还可以启用自动架构生成功能，该功能获取您的数据来源，并生成在架构中访问它所需的一些 CRUD、`List` 和 `Query` 操作。

      对于 OpenSearch，您必须选择您的区域，然后选择该区域中的域（集群）。您可以选择创建新的通用表角色或导入表的现有角色，以规定与域交互的规则。

      对于 Lambda，必须选择您的区域，然后选择该区域中的 Lambda 函数的 ARN。您可以选择创建新的通用表角色或导入表的现有角色，以规定与 Lambda 函数交互的规则。

      对于 HTTP，必须输入您的 HTTP 终端节点。

      对于 EventBridge，你必须选择你所在的地区，然后选择该地区的活动巴士。您可以选择创建新的通用表角色或导入表的现有角色，以规定与事件总线交互的规则。

      对于 RDS，必须选择您的区域，然后选择密钥存储（用户名和密码）、数据库名称和架构。

      对于“None”，您将添加一个没有实际数据来源的数据来源。这是为了在本地处理解析器，而不是通过实际数据来源。
**注意**  
如果要导入现有的角色，它们需要使用信任策略。有关更多信息，请参阅 [IAM 信任策略](#iam-trust-policy.title)。

1. 选择**创建**。
**注意**  
或者，如果要创建 DynamoDB 数据来源，您可以转到控制台中的**架构**页面，选择页面顶部的**创建资源**，然后填写一个预定义模型以转换为表。在该选项中，您填写或导入基本类型，配置包括分区键在内的基本表数据，并检查架构更改。

------
#### [ CLI ]
+ 运行 [https://docs.aws.amazon.com/cli/latest/reference/appsync/create-data-source.html](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-data-source.html) 命令以创建数据来源。

  您需要为该特定命令输入一些参数：

  1. 您的 API 的 `api-id`。

  1. 您的表的 `name`。

  1. 数据来源的 `type`。根据您选择的数据来源类型，您可能需要输入 `service-role-arn` 和 `-config` 标签。

  示例命令可能如下所示：

  ```
   aws appsync create-data-source --api-id abcdefghijklmnopqrstuvwxyz --name data_source_name --type data_source_type --service-role-arn arn:aws:iam::107289374856:role/role_name --[data_source_type]-config {params}
  ```

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我们建议您查看 CDK 的[官方文档](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 [CD](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 AWS AppSync  
下面列出的步骤仅显示用于添加特定资源的一般代码片段示例。这**并不**意味着，它是您的生产代码中的有效解决方案。我们还假设您已具有正常工作的应用程序。

要添加您的特定数据来源，您需要将构造添加到堆栈文件中。可以在此处找到一个数据来源类型列表：
+  [ DynamoDbDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.DynamoDbDataSource.html) 
+  [ EventBridgeDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.EventBridgeDataSource.html) 
+  [ HttpDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.HttpDataSource.html) 
+  [ LambdaDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.LambdaDataSource.html) 
+  [ NoneDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.NoneDataSource.html) 
+  [ OpenSearchDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.OpenSearchDataSource.html) 
+  [ RdsDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.RdsDataSource.html) 

1. 一般来说，您可能需要将 import 指令添加到您使用的服务中。例如，它可能采用以下形式：

   ```
   import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
   import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
   ```

   例如，您可以通过以下方式导入 AWS AppSync 和 DynamoDB 服务：

   ```
   import * as appsync from 'aws-cdk-lib/aws-appsync';
   import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
   ```

1. 某些服务（例如 RDS）要求在创建数据来源之前在堆栈文件中进行一些额外的设置（例如，VPC 创建、角色和访问凭证）。有关更多信息，请参阅相关 CDK 页面中的示例。

1. 对于大多数数据源，尤其是 AWS 服务，您将在堆栈文件中创建数据源的新实例。通常，这会如下所示：

   ```
   const add_data_source_func = new service_scope.resource_name(scope: Construct, id: string, props: data_source_props);
   ```

   例如，以下是一个示例 Amazon DynamoDB 表：

   ```
   const add_ddb_table = new dynamodb.Table(this, 'Table_ID', {
     partitionKey: {
       name: 'id',
       type: dynamodb.AttributeType.STRING,
     },
     sortKey: {
       name: 'id',
       type: dynamodb.AttributeType.STRING,
     },
     tableClass: dynamodb.TableClass.STANDARD,
   });
   ```
**注意**  
大多数数据来源至少具有一个必需的属性（**不**使用 `?` 符号表示）。请参阅 CDK 文档以了解需要使用哪些属性。

1. 接下来，您需要将数据来源链接到 GraphQL API。建议的方法是，在为管道解析器创建函数时添加数据来源。例如，下面的代码片段是一个扫描 DynamoDB 表中的所有元素的函数：

   ```
   const add_func = new appsync.AppsyncFunction(this, 'func_ID', {
     name: 'func_name_in_console',
     add_api,
     dataSource: add_api.addDynamoDbDataSource('data_source_name_in_console', add_ddb_table),
     code: appsync.Code.fromInline(`
         export function request(ctx) {
           return { operation: 'Scan' };
         }
   
         export function response(ctx) {
           return ctx.result.items;
         }
     `),
     runtime: appsync.FunctionRuntime.JS_1_0_0,
   });
   ```

   在 `dataSource` 属性中，您可以调用 GraphQL API (`add_api`)，并使用其内置方法之一 (`addDynamoDbDataSource`) 在表和 GraphQL API 之间建立关联。参数是此链接的名称，该链接将存在于 AWS AppSync 控制台`data_source_name_in_console`中（在本例中）和表方法（`add_ddb_table`）。您在下一节中开始创建解析器，此时，将介绍有关该主题的更多信息。

   可以使用多种替代方法链接数据来源。从技术上讲，您可以将 `api` 添加到表函数的属性列表中。例如，以下是步骤 3 中的代码片段，但具有包含 GraphQL API 的 `api` 属性：

   ```
   const add_api = new appsync.GraphqlApi(this, 'API_ID', {
     ...
   });
   
   const add_ddb_table = new dynamodb.Table(this, 'Table_ID', {
   
    ...
   
     api: add_api
   });
   ```

   或者，您可以单独调用 `GraphqlApi` 构造：

   ```
   const add_api = new appsync.GraphqlApi(this, 'API_ID', {
     ...
   });
   
   const add_ddb_table = new dynamodb.Table(this, 'Table_ID', {
     ...
   });
   
   const link_data_source = add_api.addDynamoDbDataSource('data_source_name_in_console', add_ddb_table);
   ```

   我们建议仅在函数的属性中创建关联。否则，你要么必须在 AWS AppSync 控制台中手动将解析器函数链接到数据源（如果你想继续使用控制台值`data_source_name_in_console`），要么在函数中使用另一个名称创建单独的关联，比如`data_source_name_in_console_2`。这是由于属性处理信息的方式的限制造成的。
**注意**  
您必须重新部署应用程序才能看到更改。

------

### IAM 信任策略
<a name="iam-trust-policy"></a>

如果您为数据源使用现有 IAM 角色，则需要向该角色授予相应的权限，以便对您的 AWS 资源（例如在 Amazon DynamoDB 表`PutItem`上）执行操作。您还需要修改该角色的信任策略 AWS AppSync 以允许将其用于资源访问，如以下示例策略所示：

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
        "Effect": "Allow",
        "Principal": {
            "Service": "appsync.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
        }
    ]
}
```

------

您也可以根据需要在信任策略中添加条件，以限制对数据来源的访问。目前，可以在这些条件中使用 `SourceArn` 和 `SourceAccount` 键。例如，以下策略仅限账户 `123456789012` 访问数据来源：

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "appsync.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "123456789012"
        }
      }
    }
  ]
}
```

------

或者，您可以使用以下策略，仅限特定的 API（例如 `abcdefghijklmnopq`）访问数据来源：

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "appsync.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:appsync:us-west-2:123456789012:apis/abcdefghijklmnopq"
        }
      }
    }
  ]
}
```

------

您可以使用以下策略将访问权限限制为 AWS AppSync APIs 来自特定区域的所有人`us-east-1`，例如：

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "appsync.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:appsync:us-east-1:123456789012:apis/*"
        }
      }
    }
  ]
}
```

------

在下一节（[配置解析器](https://docs.aws.amazon.com//appsync/latest/devguide/resolver-config-overview.html)）中，我们将添加解析器业务逻辑，并将其附加到架构中的字段以处理数据来源中的数据。

有关角色策略配置的更多信息，请参阅《IAM 用户指南》中的[修改角色](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_roles_manage_modify.html)。**

有关解析人员的跨账户访问权限的更多信息 AWS AppSync，请参阅为[构建跨账户 AWS LambdaAWS Lambda](https://aws.amazon.com/blogs/mobile/appsync-lambda-cross-account/)解析器。 AWS AppSync

# 在 AWS AppSync 中配置解析器
<a name="resolver-config-overview"></a>

在前面的章节中，您了解了如何创建 GraphQL 架构和数据来源，然后在 AWS AppSync 服务中将它们链接在一起。在您的架构中，您可能已在查询和变更中创建了一个或多个字段（操作）。虽然该架构描述了操作从数据来源请求的数据类型，但从未实施这些操作如何处理数据的行为。

操作的行为始终是在解析器中实施的，解析器将链接到执行操作的字段。有关解析器一般如何工作的更多信息，请参阅[解析器](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)页面。

在 AWS AppSync 中，解析器与运行时系统相关联，即，在其中执行解析器的环境。运行时系统决定了编写解析器时使用的语言。目前支持两种运行时系统：APPSYNC\$1JS (JavaScript) 和 Apache Velocity 模板语言 (VTL)。

在实施解析器时，它们采用通用的结构：
+ **预备步骤**：在客户端发出请求时，将为使用的架构字段（通常是查询、变更、订阅）的解析器传送请求的数据。解析器开始使用预备步骤处理程序处理请求数据，该处理程序允许在数据传送到解析器之前执行一些预处理操作。
+ **函数**：在运行预备步骤后，请求传送到函数列表。将对数据来源执行列表中的第一个函数。函数是解析器代码的子集，其中包含自己的请求和响应处理程序。请求处理程序将获取请求数据，并对数据来源执行操作。在将数据来源的响应传回到列表之前，响应处理程序对其进行处理。如果具有多个函数，请求数据将发送到列表中的下一个函数以进行执行。列表中的函数按照开发人员定义的顺序依次执行。在执行所有函数后，最终结果传送到后续步骤。
+ **后续步骤**：后续步骤是一个处理程序函数，允许您在将最终函数的响应传送到 GraphQL 响应之前对其执行一些最终操作。

该流程是一个管道解析器示例。在两个运行时系统中都支持管道解析器。不过，这仅简要说明了管道解析器的用途。此外，我们仅介绍一种可能的解析器配置。有关支持的解析器配置的更多信息，请参阅适用于 APPSYNC\$1JS 的 [JavaScript 解析器概述](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)或适用于 VTL 的[解析器映射模板概述](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-overview.html)。

正如您看到的一样，解析器是模块化的。要使解析器的组件正常工作，它们必须能够从其他组件了解执行状态。从[解析器](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)一节中，您知道可以将有关执行状态的重要信息作为一组参数（`args`、`context` 等）传递给解析器中的每个组件。在 AWS AppSync 中，这是由 `context` 严格处理的。它是一个容器，用于存放有关解析的字段的信息。这可能包括传递的参数、结果、授权数据、标头数据等所有内容。有关上下文的更多信息，请参阅适用于 APPSYNC\$1JS 的[解析器上下文对象参考](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)或适用于 VTL 的[解析器映射模板上下文参考](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html)。

上下文并不是可用于实施解析器的唯一工具。AWS AppSync 支持广泛的实用程序，用于值生成、错误处理、解析、转换等。您可以在[此处](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)查看 APPSYNC\$1JS 的实用程序列表，或者在[此处](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html)查看 VTL 的实用程序列表。

在以下几节中，您将了解如何在 GraphQL API 中配置解析器。

**Topics**
+ [创建基本查询 (JavaScript)](configuring-resolvers-js.md)
+ [创建基本查询（VTL）](configuring-resolvers.md)

# 创建基本查询 (JavaScript)
<a name="configuring-resolvers-js"></a>

GraphQL 解析器将类型的架构中的字段连接到数据来源。解析器是用于完成请求的机制。

正在 AWS AppSync 使用解析器 JavaScript 将 GraphQL 表达式转换为数据源可以使用的格式。或者，可以使用 [Apache Velocity 模板语言 (VTL)](https://velocity.apache.org/engine/2.0/vtl-reference.html) 编写映射模板，以将 GraphQL 表达式转换为数据来源可使用的格式。

本节介绍如何使用 JavaScript配置解析器。解[析器教程 (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html) 部分提供了有关如何使用实现解析器的深入教程。 JavaScript[Resolver 参考 (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html) 部分解释了可与解 JavaScript 析器一起使用的实用程序操作。

我们建议您在尝试使用任何上述教程之前先遵循本指南。

在本节中，我们将介绍如何为查询和变更创建和配置解析器。

**注意**  
本指南假设您已创建架构并至少具有一个查询或变更。如果您要获取订阅（实时数据），请参阅[本](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html)指南。

在本节中，我们提供一些配置解析器的常规步骤以及一个使用以下架构的示例：

```
// schema.graphql file

input CreatePostInput {
  title: String
  date: AWSDateTime
}

type Post {
  id: ID!
  title: String
  date: AWSDateTime
}

type Mutation {
  createPost(input: CreatePostInput!): Post
}

type Query {
  getPost: [Post]
}
```

## 创建基本查询解析器
<a name="create-basic-query-resolver-js"></a>

本节说明了如何创建基本查询解析器。

------
#### [ Console ]

1. 登录 AWS 管理控制台 并打开[AppSync控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**APIs 控制面板**中，选择你的 GraphQL API。

   1. 在**侧边栏**中，选择**架构**。

1. 输入架构和数据来源详细信息。有关更多信息，请参阅[设计架构](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html)和[附加数据来源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)小节。

1. 在**架构**编辑器旁边，具有一个名为**解析器**的窗口。该框包含**架构**窗口中定义的类型和字段列表。您可以将解析器附加到字段。您很可能会将解析器附加到字段操作。在本节中，我们将了解简单的查询配置。在 **Query** 类型下面，选择您的查询字段旁边的**附加**。

1. 在**附加解析器**页面上的**解析器类型**下面，您可以在管道解析器和单位解析器之间进行选择。有关这些类型的更多信息，请参阅[解析器](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)。本指南将使用`pipeline resolvers`。
**提示**  
在创建管道解析器时，您的数据来源将附加到管道函数。函数是在您创建管道解析器本身之后创建的，这就是为什么在该页面中没有设置数据来源的选项。如果您使用单位解析器，则数据来源直接绑定到解析器，因此，您可以在该页面中设置数据来源。

   对于 **Resolver 运行时**`APPSYNC_JS`，选择启用 JavaScript 运行时。

1. 您可以为该 API 启用[缓存](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html)。我们建议暂时关闭该功能。选择**创建**。

1. 在**编辑解析器**页面上，具有一个名为**解析器代码**的代码编辑器，可用于实施解析器处理程序和响应的逻辑（预备步骤和后续步骤）。有关更多信息，请参阅[JavaScript解析器概述](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)。
**注意**  
在我们的示例中，我们直接将请求保留空白，并将响应设置为从[上下文](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)返回最后的数据来源结果：  

   ```
   import {util} from '@aws-appsync/utils';
   
   export function request(ctx) {
       return {};
   }
   
   export function response(ctx) {
       return ctx.prev.result;
   }
   ```

   在该部分下面，具有有一个名为**函数**的表。函数用于实施可以在多个解析器中重复使用的代码。您可以将源代码存储为函数以在需要时添加到解析器中，而不是不断重新编写或复制代码。

   函数占据了管道的操作列表中的很大部分。在解析器中使用多个函数时，您可以设置函数顺序，将按该顺序运行它们。它们在请求函数运行之后和响应函数开始之前执行。

   要添加新函数，请在**函数**下面选择**添加函数**，然后选择**创建新函数**。或者，您可能会看到一个**创建函数**按钮可供选择。

   1. 选择一个数据来源。这是解析器处理的数据来源。
**注意**  
在我们的示例中，我们为 `getPost` 附加一个解析器，它按 `id` 检索 `Post` 对象。假设我们已为该架构设置一个 DynamoDB 表。其分区键设置为 `id` 并且为空。

   1. 输入一个`Function name`。

   1. 在**函数代码**下面，您需要实施函数的行为。这可能会令人困惑，但每个函数具有自己的本地请求和响应处理程序。先运行请求，然后调用数据来源以处理请求，最后由响应处理程序处理数据来源响应。结果存储在[上下文](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)对象中。然后，运行列表中的下一个函数；如果是最后一个函数，则将其传递给后续步骤响应处理程序。
**注意**  
在我们的示例中，我们将一个解析器附加到 `getPost`，它从数据来源获取 `Post` 对象列表。我们的请求函数将从我们的表中请求数据，表将其响应传递给上下文 (ctx)，然后响应将在上下文中返回结果。 AWS AppSync的优势在于它与其他服务的互连性。 AWS 由于我们使用的是 DynamoDB，因此，我们具有[一组操作](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html)以简化此类操作。我们还具有其他数据来源类型的一些样板示例。  
我们的代码将如下所示：  

      ```
      import { util } from '@aws-appsync/utils';
      
      /**
       * Performs a scan on the dynamodb data source
       */
      export function request(ctx) {
        return { operation: 'Scan' };
      }
      
      /**
       * return a list of scanned post items
       */
      export function response(ctx) {
        return ctx.result.items;
      }
      ```
在该步骤中，我们添加了两个函数：  
`request`：请求处理程序对数据来源执行检索操作。参数包含上下文对象 (`ctx`) 或为执行特定操作的所有解析器提供的一些数据。例如，它可能包含授权数据、解析的字段名称等。返回语句执行 [https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan](https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan) 操作（请参阅[此处](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html)的示例）。由于我们使用的是 DynamoDB，因此，我们可以使用该服务中的一些操作。扫描对表中的所有项目执行基本获取。该操作的结果作为 `result` 容器存储在上下文对象中，然后再传递给响应处理程序。`request` 在管道中的响应之前运行。
`response`：返回 `request` 输出的响应处理程序。参数是更新的上下文对象，返回语句是 `ctx.prev.result`。在本指南的当前阶段，您可能还不熟悉该值。`ctx` 指的是上下文对象。`prev` 指的是管道中的以前操作，也就是 `request`。`result` 包含在管道中执行解析器的结果。如果将它们放在一起，`ctx.prev.result` 将返回最后执行的操作的结果，即请求处理程序。

   1. 在完成后，选择**创建**。

1. 返回到解析器屏幕，在**函数**下面选择**添加函数**下拉列表，然后将您的函数添加到函数列表中。

1. 选择**保存**以更新解析器。

------
#### [ CLI ]

**添加您的函数**
+ 使用 `[create-function](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-function.html)` 命令为管道解析器创建一个函数。

  您需要为该特定命令输入一些参数：

  1. 您的 API 的 `api-id`。

  1.  AWS AppSync 控制台`name`中该函数的。

  1. `data-source-name` 或函数使用的数据来源名称。它必须已创建并链接到 AWS AppSync 服务中的 GraphQL API。

  1. `runtime` 或函数的环境和语言。对于 JavaScript，名称必须为`APPSYNC_JS`，运行时必须为`1.0.0`。

  1. `code` 或函数的请求和响应处理程序。虽然您可以手动键入该内容，但将其添加到 .txt 文件（或类似格式）并作为参数传入要容易得多。
**注意**  
我们的查询代码将位于作为参数传入的文件中：  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Performs a scan on the dynamodb data source
      */
     export function request(ctx) {
       return { operation: 'Scan' };
     }
     
     /**
      * return a list of scanned post items
      */
     export function response(ctx) {
       return ctx.result.items;
     }
     ```

  示例命令可能如下所示：

  ```
  aws appsync create-function \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --name get_posts_func_1 \
  --data-source-name table-for-posts \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file://~/path/to/file/{filename}.{fileType}
  ```

  将在 CLI 中返回输出。示例如下：

  ```
  {
      "functionConfiguration": {
          "functionId": "ejglgvmcabdn7lx75ref4qeig4",
          "functionArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/functions/ejglgvmcabdn7lx75ref4qeig4",
          "name": "get_posts_func_1",
          "dataSourceName": "table-for-posts",
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```
**注意**  
确保将 `functionId` 记录在某处，因为它用于将函数附加到解析器。

**创建您的解析器**
+ 运行 `[create-resolver](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)` 命令，为 `Query` 创建一个管道函数。

  您需要为该特定命令输入一些参数：

  1. 您的 API 的 `api-id`。

  1. `type-name` 或架构中的特殊对象类型（查询、变更、订阅）。

  1. `field-name` 或要将解析器附加到的特殊对象类型中的字段操作。

  1. `kind`，它指定单位解析器或管道解析器。请将其设置为 `PIPELINE` 以启用管道函数。

  1. `pipeline-config` 或附加到解析器的函数。确保您知道函数的 `functionId` 值。列表顺序很重要。

  1. 那是`runtime`，那是 `APPSYNC_JS` (JavaScript)。`runtimeVersion` 目前是 `1.0.0`。

  1. `code`，它包含预备步骤和后续步骤处理程序。
**注意**  
我们的查询代码将位于作为参数传入的文件中：  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       const { id, ...values } = ctx.args;
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({ id }),
         attributeValues: util.dynamodb.toMapValues(values),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  示例命令可能如下所示：

  ```
  aws appsync create-resolver \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --type-name Query \
  --field-name getPost \
  --kind PIPELINE \
  --pipeline-config functions=ejglgvmcabdn7lx75ref4qeig4 \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  将在 CLI 中返回输出。示例如下：

  ```
  {
      "resolver": {
          "typeName": "Mutation",
          "fieldName": "getPost",
          "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation/resolvers/getPost",
          "kind": "PIPELINE",
          "pipelineConfig": {
              "functions": [
                  "ejglgvmcabdn7lx75ref4qeig4"
              ]
          },
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我们建议您查看 CDK 的[官方文档](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 [CD](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 AWS AppSync  
下面列出的步骤仅显示用于添加特定资源的一般代码片段示例。这**并不**意味着，它是您的生产代码中的有效解决方案。我们还假设您已具有正常工作的应用程序。

基本应用程序需要使用以下内容：

1. 服务导入指令

1. 架构代码

1. 数据来源生成器

1. 函数代码

1. 解析器代码

从[设计您的架构](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html)和[附加数据来源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)小节中，我们知道堆栈文件将包含以下格式的 import 指令：

```
import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
```

**注意**  
在前面的章节中，我们只说明了如何导入 AWS AppSync 构造。在实际代码中，您必须导入更多服务才能运行应用程序。在我们的示例中，如果我们要创建一个非常简单的 CDK 应用程序，我们至少要导入该 AWS AppSync 服务以及我们的数据源，即 DynamoDB 表。我们还需要导入一些额外的构造以部署应用程序：  

```
import * as cdk from 'aws-cdk-lib';
import * as appsync from 'aws-cdk-lib/aws-appsync';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';
```
简要说明一下每个指令：  
`import * as cdk from 'aws-cdk-lib';`：用于定义 CDK 应用程序和构造，例如堆栈。它还包含一些对我们的应用程序非常有用的实用程序函数，例如处理元数据。如果您熟悉该 import 指令，但想知道为什么此处没有使用 cdk 核心库，请参阅 [Migration](https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html) 页面。
`import * as appsync from 'aws-cdk-lib/aws-appsync';`：它导入 [AWS AppSync 服务](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)。
`import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';`：它导入 [DynamoDB 服务](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb-readme.html)。
`import { Construct } from 'constructs';`：我们需要使用该指令以定义根[构造](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html)。

导入类型取决于您调用的服务。我们建议查看 CDK 文档以获取示例。页面顶部的架构是 CDK 应用程序中的单独文件，显示为 `.graphql` 文件。在堆栈文件中，我们可以使用以下格式将其与新的 GraphQL 相关联：

```
const add_api = new appsync.GraphqlApi(this, 'graphQL-example', {
  name: 'my-first-api',
  schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'schema.graphql')),
});
```

**注意**  
在 `add_api` 范围内，我们使用 `new` 关键字和后面的 `appsync.GraphqlApi(scope: Construct, id: string , props: GraphqlApiProps)` 添加新的 GraphQL API。我们的范围是 `this`，CFN ID 是 `graphQL-example`，我们的属性是 `my-first-api`（控制台中的 API 的名称）和 `schema.graphql`（架构文件的绝对路径）。

要添加数据来源，您必须先将数据来源添加到堆栈中。然后，您需要使用源特定的方法将其与 GraphQL API 相关联。在您创建解析器函数时，将会发生关联。同时，让我们使用一个通过 `dynamodb.Table` 创建 DynamoDB 表的示例：

```
const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
  partitionKey: {
    name: 'id',
    type: dynamodb.AttributeType.STRING,
  },
});
```

**注意**  
如果我们要在示例中使用该表，我们将添加一个 CFN ID 为 `posts-table` 且分区键为 `id (S)` 的新 DynamoDB 表。

接下来，我们需要在堆栈文件中实施解析器。以下是扫描 DynamoDB 表中的所有项目的简单查询示例：

```
const add_func = new appsync.AppsyncFunction(this, 'func-get-posts', {
  name: 'get_posts_func_1',
  add_api,
  dataSource: add_api.addDynamoDbDataSource('table-for-posts', add_ddb_table),
  code: appsync.Code.fromInline(`
      export function request(ctx) {
        return { operation: 'Scan' };
      }

      export function response(ctx) {
        return ctx.result.items;
      }
  `),
  runtime: appsync.FunctionRuntime.JS_1_0_0,
});

new appsync.Resolver(this, 'pipeline-resolver-get-posts', {
  add_api,
  typeName: 'Query',
  fieldName: 'getPost',
  code: appsync.Code.fromInline(`
      export function request(ctx) {
        return {};
      }

      export function response(ctx) {
        return ctx.prev.result;
      }
 `),
  runtime: appsync.FunctionRuntime.JS_1_0_0,
  pipelineConfig: [add_func],
});
```

**注意**  
首先，我们创建一个名为 `add_func` 的函数。这种创建顺序可能看起来有点违背常理，但您必须在创建管道解析器本身之前在解析器中创建函数。函数采用以下格式：  

```
AppsyncFunction(scope: Construct, id: string, props: AppsyncFunctionProps)
```
我们的范围是 `this`，CFN ID 是 `func-get-posts`，属性包含实际函数详细信息。我们在属性中包含：  
 AWS AppSync 控制台中将出现的函数 (`get_posts_func_1`)。`name`
我们以前创建的 GraphQL API (`add_api`)。
数据来源；我们在其中将数据来源链接到 GraphQL API 值，然后将其附加到函数。我们获取创建的表 (`add_ddb_table`)，并使用 `GraphqlApi` 方法之一 ([https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options)) 将其附加到 GraphQL API (`add_api`)。ID 值 (`table-for-posts`) 是 AWS AppSync 控制台中的数据来源的名称。有关源特定的方法列表，请参阅以下页面：  
[ DynamoDbDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.DynamoDbDataSource.html) 
 [ EventBridgeDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.EventBridgeDataSource.html) 
 [ HttpDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.HttpDataSource.html) 
 [ LambdaDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.LambdaDataSource.html) 
 [ NoneDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.NoneDataSource.html) 
 [ OpenSearchDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.OpenSearchDataSource.html) 
 [ RdsDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.RdsDataSource.html) 
代码包含函数的请求和响应处理程序，这是简单的扫描和返回。
运行时系统指定我们要使用 APPSYNC\$1JS 运行时系统 1.0.0 版。请注意，这是目前唯一适用于 APPSYNC\$1JS 的版本。
接下来，我们需要将函数附加到管道解析器。我们使用以下格式创建解析器：  

```
Resolver(scope: Construct, id: string, props: ResolverProps)
```
我们的范围是 `this`，CFN ID 是 `pipeline-resolver-get-posts`，属性包含实际函数详细信息。我们在属性中包含：  
我们以前创建的 GraphQL API (`add_api`)。
特殊对象类型名称；这是一个查询操作，因此，我们直接添加了 `Query` 值。
字段名称 (`getPost`) 是架构中的 `Query` 类型下面的字段名称。
代码包含预备步骤处理程序和后续步骤处理程序。我们的示例仅返回函数执行操作后在上下文中包含的任何结果。
运行时系统指定我们要使用 APPSYNC\$1JS 运行时系统 1.0.0 版。请注意，这是目前唯一适用于 APPSYNC\$1JS 的版本。
管道配置包含对我们创建的函数 (`add_func`) 的引用。

------

为了总结此示例中发生的情况，您看到了一个实现请求和响应处理程序的 AWS AppSync 函数。该函数负责与您的数据来源进行交互。请求处理程序向其发送了一个`Scan`操作 AWS AppSync，指示其对您的 DynamoDB 数据源执行什么操作。响应处理程序返回项目列表 (`ctx.result.items`)。然后，将项目列表自动映射到 `Post` GraphQL 类型。

## 创建基本变更解析器
<a name="creating-basic-mutation-resolvers-js"></a>

本节说明了如何创建基本变更解析器。

------
#### [ Console ]

1. 登录 AWS 管理控制台 并打开[AppSync控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**APIs 控制面板**中，选择你的 GraphQL API。

   1. 在**侧边栏**中，选择**架构**。

1. 在**解析器**部分的 **Mutation** 类型下面，选择您的字段旁边的**附加**。
**注意**  
在我们的示例中，我们为 `createPost` 附加一个解析器，它将 `Post` 对象添加到我们的表中。假设我们使用上一节中的相同 DynamoDB 表。其分区键设置为 `id` 并且为空。

1. 在**附加解析器**页面上的**解析器类型**下面，选择`pipeline resolvers`。提醒一下，您可以在[此处](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)找到有关解析器的更多信息。对于 **Resolver 运行时**`APPSYNC_JS`，选择启用 JavaScript 运行时。

1. 您可以为该 API 启用[缓存](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html)。我们建议暂时关闭该功能。选择**创建**。

1. 选择**添加函数**，然后选择**创建新函数**。或者，您可能会看到一个**创建函数**按钮可供选择。

   1. 选择您的 数据来源。这应该是使用变更处理数据的源。

   1. 输入一个`Function name`。

   1. 在**函数代码**下面，您需要实施函数的行为。这是一个变更，因此，理想情况下，请求将对调用的数据来源执行某种状态更改操作。结果由响应函数进行处理。
**注意**  
`createPost` 在表中添加或“放置”新的 `Post`，并将我们的参数作为数据。我们可能会添如下内容：  

      ```
      import { util } from '@aws-appsync/utils';
      
      /**
       * Sends a request to `put` an item in the DynamoDB data source
       */
      export function request(ctx) {
        return {
          operation: 'PutItem',
          key: util.dynamodb.toMapValues({id: util.autoId()}),
          attributeValues: util.dynamodb.toMapValues(ctx.args.input),
        };
      }
      
      /**
       * returns the result of the `put` operation
       */
      export function response(ctx) {
        return ctx.result;
      }
      ```
在该步骤中，我们还添加了 `request` 和 `response` 函数：  
`request`：请求处理程序接受上下文以作为参数。请求处理程序返回语句执行 [https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem](https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem) 命令，这是内置的 DynamoDB 操作（请参阅[此处](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/getting-started-step-2.html)或[此处](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.WritingData)的示例）。`PutItem` 命令获取分区 `key` 值（由 `util.autoid()` 自动生成）以及来自上下文参数输入的 `attributes`（这些是在请求中传递的值），以将 `Post` 对象添加到我们的 DynamoDB 表中。`key` 是 `id`，`attributes` 是 `date` 和 `title` 字段参数。它们通过 [https://docs.aws.amazon.com//appsync/latest/devguide/dynamodb-helpers-in-util-dynamodb-js.html#utility-helpers-in-toMap-js](https://docs.aws.amazon.com//appsync/latest/devguide/dynamodb-helpers-in-util-dynamodb-js.html#utility-helpers-in-toMap-js) 帮助程序预先设置格式以与 DynamoDB 表一起使用。
`response`：响应接受更新的上下文，并返回请求处理程序的结果。

   1. 在完成后，选择**创建**。

1. 返回到解析器屏幕，在**函数**下面选择**添加函数**下拉列表，然后将您的函数添加到函数列表中。

1. 选择**保存**以更新解析器。

------
#### [ CLI ]

**添加您的函数**
+ 使用 `[create-function](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-function.html)` 命令为管道解析器创建一个函数。

  您需要为该特定命令输入一些参数：

  1. 您的 API 的 `api-id`。

  1.  AWS AppSync 控制台`name`中该函数的。

  1. `data-source-name` 或函数使用的数据来源名称。它必须已创建并链接到 AWS AppSync 服务中的 GraphQL API。

  1. `runtime` 或函数的环境和语言。对于 JavaScript，名称必须为`APPSYNC_JS`，运行时必须为`1.0.0`。

  1. `code` 或函数的请求和响应处理程序。虽然您可以手动键入该内容，但将其添加到 .txt 文件（或类似格式）并作为参数传入要容易得多。
**注意**  
我们的查询代码将位于作为参数传入的文件中：  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({id: util.autoId()}),
         attributeValues: util.dynamodb.toMapValues(ctx.args.input),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  示例命令可能如下所示：

  ```
  aws appsync create-function \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --name add_posts_func_1 \
  --data-source-name table-for-posts \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  将在 CLI 中返回输出。示例如下：

  ```
  {
      "functionConfiguration": {
          "functionId": "vulcmbfcxffiram63psb4dduoa",
          "functionArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/functions/vulcmbfcxffiram63psb4dduoa",
          "name": "add_posts_func_1",
          "dataSourceName": "table-for-posts",
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output foes here"
      }
  }
  ```
**注意**  
确保将 `functionId` 记录在某处，因为它用于将函数附加到解析器。

**创建您的解析器**
+ 运行 `[create-resolver](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)` 命令，为 `Mutation` 创建一个管道函数。

  您需要为该特定命令输入一些参数：

  1. 您的 API 的 `api-id`。

  1. `type-name` 或架构中的特殊对象类型（查询、变更、订阅）。

  1. `field-name` 或要将解析器附加到的特殊对象类型中的字段操作。

  1. `kind`，它指定单位解析器或管道解析器。请将其设置为 `PIPELINE` 以启用管道函数。

  1. `pipeline-config` 或附加到解析器的函数。确保您知道函数的 `functionId` 值。列表顺序很重要。

  1. 那是`runtime`，那是 `APPSYNC_JS` (JavaScript)。`runtimeVersion` 目前是 `1.0.0`。

  1. `code`，它包含预备步骤和后续步骤。
**注意**  
我们的查询代码将位于作为参数传入的文件中：  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       const { id, ...values } = ctx.args;
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({ id }),
         attributeValues: util.dynamodb.toMapValues(values),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  示例命令可能如下所示：

  ```
  aws appsync create-resolver \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --type-name Mutation \
  --field-name createPost \
  --kind PIPELINE \
  --pipeline-config functions=vulcmbfcxffiram63psb4dduoa \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  将在 CLI 中返回输出。示例如下：

  ```
  {
      "resolver": {
          "typeName": "Mutation",
          "fieldName": "createPost",
          "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation/resolvers/createPost",
          "kind": "PIPELINE",
          "pipelineConfig": {
              "functions": [
                  "vulcmbfcxffiram63psb4dduoa"
              ]
          },
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我们建议您查看 CDK 的[官方文档](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 [CD](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 AWS AppSync  
下面列出的步骤仅显示用于添加特定资源的一般代码片段示例。这**并不**意味着，它是您的生产代码中的有效解决方案。我们还假设您已具有正常工作的应用程序。
+ 要创建变更，假设您使用同一项目，您可以将其添加到堆栈文件中，就像查询一样。以下是修改的函数和解析器，用于在表中添加新 `Post` 的变更：

  ```
  const add_func_2 = new appsync.AppsyncFunction(this, 'func-add-post', {
    name: 'add_posts_func_1',
    add_api,
    dataSource: add_api.addDynamoDbDataSource('table-for-posts-2', add_ddb_table),
        code: appsync.Code.fromInline(`
            export function request(ctx) {
              return {
                operation: 'PutItem',
                key: util.dynamodb.toMapValues({id: util.autoId()}),
                attributeValues: util.dynamodb.toMapValues(ctx.args.input),
              };
            }
  
            export function response(ctx) {
              return ctx.result;
            }
        `), 
    runtime: appsync.FunctionRuntime.JS_1_0_0,
  });
  
  new appsync.Resolver(this, 'pipeline-resolver-create-posts', {
    add_api,
    typeName: 'Mutation',
    fieldName: 'createPost',
        code: appsync.Code.fromInline(`
            export function request(ctx) {
              return {};
            }
  
            export function response(ctx) {
              return ctx.prev.result;
            }
        `),
    runtime: appsync.FunctionRuntime.JS_1_0_0,
    pipelineConfig: [add_func_2],
  });
  ```
**注意**  
由于该变更和查询的结构相似，因此，我们仅介绍为创建变更而进行的更改。  
在该函数中，我们将 CFN ID 更改为 `func-add-post` 并将名称更改为 `add_posts_func_1`，以反映我们将 `Posts` 添加到表中的情况。在数据源中，我们在 AWS AppSync 控制台中与表 (`add_ddb_table`) 建立了新的关联，`table-for-posts-2`因为该`addDynamoDbDataSource`方法需要它。请记住，这个新的关联仍在使用我们之前创建的同一个表，但是我们现在在 AWS AppSync 控制台中有两个与它的连接：一个用于查询 as`table-for-posts`，另一个用于变异为`table-for-posts-2`。代码进行了更改以添加 `Post`，方法是自动生成其 `id` 值，并接受客户端输入以用于其余字段。  
在解析器中，我们将 id 值更改为 `pipeline-resolver-create-posts` 以反映我们将 `Posts` 添加到表中的情况。为了反映架构中的变更，类型名称更改为 `Mutation`，名称更改为 `createPost`。管道配置设置为我们的新变更函数 `add_func_2`。

------

为了总结本示例中发生的情况， AWS AppSync 自动将`createPost`字段中定义的参数从 GraphQL 架构转换为 DynamoDB 操作。该示例使用 `id` 键将记录存储在 DynamoDB 中，该键是使用我们的 `util.autoId()` 帮助程序自动创建的。您通过 AWS AppSync 控制台或其他方式发出的请求传递给上下文参数 (`ctx.args.input`) 的所有其他字段都将存储为表的属性。键和属性使用 `util.dynamodb.toMapValues(values)` 帮助程序自动映射到兼容的 DynamoDB 格式。

AWS AppSync 还支持用于编辑解析器的测试和调试工作流程。您可以在调用模板之前使用模拟 `context` 对象查看转换的模板值。或者，您可以选择在运行查询时以交互方式查看对数据来源的完整请求。有关更多信息，请参阅[测试和调试解析器 (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/test-debug-resolvers-js.html) 和[监控和日志记录](https://docs.aws.amazon.com/appsync/latest/devguide/monitoring.html#aws-appsync-monitoring)。

## 高级解析器
<a name="advanced-resolvers-js"></a>

如果您按照[设计您的架构](designing-your-schema.md#aws-appsync-designing-your-schema)中的可选分页一节进行操作，您仍然需要将解析器添加到请求才能使用分页。我们的示例使用名为 `getPosts` 的查询分页，每次仅返回一部分请求内容。该字段上的解析器代码可能如下所示：

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  const { limit = 20, nextToken } = ctx.args;
  return { operation: 'Scan', limit, nextToken };
}

/**
 * @returns the result of the `put` operation
 */
export function response(ctx) {
  const { items: posts = [], nextToken } = ctx.result;
  return { posts, nextToken };
}
```

在请求中，我们传入请求的上下文。我们`limit`的 is*20*，这意味着我们在第一个查询`Posts`中最多返回 20。`nextToken` 光标固定在数据来源中的第一个 `Post` 条目。这些内容将传递给参数。然后，请求执行从第一个 `Post` 到扫描限制数的扫描。数据来源将结果存储在上下文中，该结果将传递给响应。响应返回它检索的 `Posts`，然后将 `nextToken` 设置为紧靠限制后面的 `Post` 条目。发出的下一个请求执行完全相同的操作，但从紧靠第一个查询后面的偏移开始。请记住，这些类型的请求是按顺序完成的，而不是并行完成的。

# 在 AWS AppSync () JavaScript 中测试和调试解析器
<a name="test-debug-resolvers-js"></a>

AWS AppSync 针对数据源对 GraphQL 字段执行解析器。在使用管道解析器时，函数与数据来源交互。如[JavaScript 解析器概述中所述](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)，函数通过使用写入运行时并在运行时运行的请求和响应处理程序与数据源进行通信。 JavaScript `APPSYNC_JS`这样，您就可以在与数据来源通信之前和之后提供自定义逻辑和条件。

为了帮助开发者编写、测试和调试这些解析器， AWS AppSync 控制台还提供了一些工具，用于创建 GraphQL 请求和响应，并将模拟数据传递给各个字段解析器。此外，您还可以在 AWS AppSync 控制台中执行查询、变更和订阅，并查看来自 Amazon CloudWatch 的整个请求的详细日志流。这包括来自数据来源的结果。

## 使用模拟数据进行测试
<a name="testing-with-mock-data-js"></a>

在调用 GraphQL 解析器时，它包含一个 `context` 对象，其中包含有关请求的相关信息。其中包括来自客户端的参数、身份信息以及 GraphQL 父字段的数据。它还存储来自数据来源的结果，可以在响应处理程序中使用这些结果。有关该结构以及编程时使用的可用帮助程序实用程序的更多信息，请参阅[解析器上下文对象参考](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)。

在编写或编辑解析器函数时，您可以将*模拟* 或*测试上下文* 对象传递到控制台编辑器中。这样，您就可以了解请求和响应处理程序如何进行评估，而无需实际对数据来源运行。例如，您可以传递测试 `firstname: Shaggy` 参数，观察在您的模板代码中使用 `ctx.args.firstname` 时如何评估。您还可以测试任何实用程序帮助程序（例如 `util.autoId()` 或 `util.time.nowISO8601()`）的评估。

### 测试解析器
<a name="test-a-resolver-js"></a>

此示例将使用 AWS AppSync 控制台测试解析器。

1. 登录 AWS 管理控制台 并打开[AppSync控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**APIs 控制面板**中，选择你的 GraphQL API。

   1. 在**侧边栏**中，选择**函数**。

1. 选择一个现有的函数。

1. 在**更新函数**页面顶部，选择**选择测试上下文**，然后选择**创建新上下文**。

1. 选择一个示例上下文对象，或者在下面的**配置测试上下文**窗口中手动填充 JSON。

1. 输入**测试上下文名称**。

1. 选择**保存**按钮。

1. 要使用此模拟上下文对象评估解析器，请选择 **Run Test (运行测试)**。

举一个更实际的例子，假设您具有一个存储 GraphQL 类型 `Dog` 的应用程序，该应用程序自动为对象生成 ID 并将其存储在 Amazon DynamoDB 中。您还希望通过 GraphQL 变更参数写入一些值，并仅允许特定用户查看响应。以下代码片段显示了架构的外观：

```
type Dog {
  breed: String
  color: String
}

type Mutation {
  addDog(firstname: String, age: Int): Dog
}
```

你可以编写一个 AWS AppSync 函数并将其添加到你的`addDog`解析器中来处理突变。要测试您的 AWS AppSync 函数，您可以填充上下文对象，如下例所示。以下代码拥有 `name` 和 `age` 客户端的参数，以及 `identity` 对象中填充的 `username`：

```
{
    "arguments" : {
        "firstname": "Shaggy",
        "age": 4
    },
    "source" : {},
    "result" : {
        "breed" : "Miniature Schnauzer",
        "color" : "black_grey"
    },
    "identity": {
        "sub" : "uuid",
        "issuer" : " https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
        "username" : "Nadia",
        "claims" : { },
        "sourceIp" :[  "x.x.x.x" ],
        "defaultAuthStrategy" : "ALLOW"
    }
}
```

您可以使用以下代码测试您的 AWS AppSync函数：

```
import { util } from '@aws-appsync/utils';

export function request(ctx) {
  return {
    operation: 'PutItem',
    key: util.dynamodb.toMapValues({ id: util.autoId() }),
    attributeValues: util.dynamodb.toMapValues(ctx.args),
  };
}

export function response(ctx) {
  if (ctx.identity.username === 'Nadia') {
    console.log("This request is allowed")
    return ctx.result;
  }
  util.unauthorized();
}
```

评估的请求和响应处理程序具有来自测试上下文对象的数据以及从 `util.autoId()` 中生成的值。此外，如果您要将 `username` 更改为除 `Nadia` 之外的值，将不会返回结果，因为授权检查将失败。有关精细访问控制的更多信息，请参阅[授权使用案例](security-authorization-use-cases.md#aws-appsync-security-authorization-use-cases)。

### 使用's测试请求和响应处理 AWS AppSync程序 APIs
<a name="testing-with-appsync-api-js"></a>

您可以通过 `EvaluateCode` API 命令使用模拟数据远程测试您的代码。要开始使用该命令，请确保您已将 `appsync:evaluateMappingCode` 权限添加到您的策略中。例如：

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appsync:evaluateCode",
            "Resource": "arn:aws:appsync:us-east-1:111122223333:*"
        }
    ]
}
```

------

您可以使用[AWS CLI](https://aws.amazon.com/cli/)或来利用该命令[AWS SDKs](https://aws.amazon.com/tools/)。例如，以上一节中的`Dog`架构及其 AWS AppSync 函数请求和响应处理程序为例。通过在本地工作站上使用 CLI，将代码保存到名为 `code.js` 的文件中，然后将 `context` 对象保存到名为 `context.json` 的文件中。从 Shell 中，运行以下命令：

```
$ aws appsync evaluate-code \
  --code file://code.js \
  --function response \
  --context file://context.json \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0
```

响应包含一个 `evaluationResult`，其中包含处理程序返回的负载。它还包含一个 `logs` 对象，其中保存处理程序在评估期间生成的日志列表。这样，就可以轻松调试代码执行，并查看有关评估的信息以帮助排除故障。例如：

```
{
    "evaluationResult": "{\"breed\":\"Miniature Schnauzer\",\"color\":\"black_grey\"}",
    "logs": [
        "INFO - code.js:13:5: \"This request is allowed\""
    ]
}
```

可以将 `evaluationResult` 解析为 JSON，其中提供：

```
{
  "breed": "Miniature Schnauzer",
  "color": "black_grey"
}
```

通过使用 SDK，您可以轻松合并常用的测试套件中的测试以验证处理程序行为。我们建议使用 [Jest 测试框架](https://jestjs.io/)创建测试，但任何测试套件都有效。以下代码片段显示假设的验证运行。请注意，我们希望评估响应是有效的 JSON ，因此，我们使用 `JSON.parse` 从字符串响应中检索 JSON：

```
const AWS = require('aws-sdk')
const fs = require('fs')
const client = new AWS.AppSync({ region: 'us-east-2' })
const runtime = {name:'APPSYNC_JS',runtimeVersion:'1.0.0')

test('request correctly calls DynamoDB', async () => {
  const code = fs.readFileSync('./code.js', 'utf8')
  const context = fs.readFileSync('./context.json', 'utf8')
  const contextJSON = JSON.parse(context)
  
  const response = await client.evaluateCode({ code, context, runtime, function: 'request' }).promise()
  const result = JSON.parse(response.evaluationResult)
  
  expect(result.key.id.S).toBeDefined()
  expect(result.attributeValues.firstname.S).toEqual(contextJSON.arguments.firstname)
})
```

 这会产生以下结果：

```
Ran all test suites.
> jest

PASS ./index.test.js
✓ request correctly calls DynamoDB (543 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 totalTime: 1.511 s, estimated 2 s
```

## 调试实时查询
<a name="debugging-a-live-query-js"></a>

除了调试生产应用程序的 end-to-end测试和日志记录之外，别无选择。 AWS AppSync 允许您使用 Amazon 记录错误和完整的请求详情 CloudWatch。此外，您可以使用 AWS AppSync 控制台测试 GraphQL 查询、突变和订阅，并将每个请求的实时日志数据流回查询编辑器进行实时调试。对于订阅而言，日志显示连接时间信息。

要执行此操作，您需要提前启用 Amazon CloudWatch 日志，如[监控和日志](monitoring.md#aws-appsync-monitoring)中所述。接下来，在 AWS AppSync 控制台中选择 “**查询**” 选项卡，然后输入有效的 GraphQL 查询。在右下部分中，单击并拖动**日志**窗口以打开“日志”视图。在页面顶部，选择“播放”箭头图标运行您的 GraphQL 查询。稍后，操作的完整请求和响应日志将流式传输到该部分，您可以在控制台中查看这些日志。

# 在 AWS AppSync () JavaScript 中配置和使用管道解析器
<a name="pipeline-resolvers-js"></a>

AWS AppSync 在 GraphQL 字段上执行解析器。在某些情况下，应用程序需要执行多个操作以解析单个 GraphQL 字段。通过使用管道解析器，开发人员现在可以编写称为“函数”的操作并按顺序执行它们。例如，管道解析器对于需要在获取字段数据之前执行授权检查的应用程序非常有用。

有关 JavaScript 管道解析器架构的更多信息，请参阅解析[JavaScript器](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html#anatomy-of-a-pipeline-resolver-js)概述。

## 步骤 1：创建管线解析器
<a name="create-a-pipeline-resolver-js"></a>

在 AWS AppSync 控制台中，转到 “**架构**” 页面。

保存以下架构：

```
schema {
    query: Query
    mutation: Mutation
}

type Mutation {
    signUp(input: Signup): User
}

type Query {
    getUser(id: ID!): User
}

input Signup {
    username: String!
    email: String!
}

type User {
    id: ID!
    username: String
    email: AWSEmail
}
```

我们将一个管道解析器连接到 **Mutation** 类型的 **signUp** 字段。在右侧的 **Mutation** 类型中，选择 `signUp` 变更字段旁边的**附加**。将解析器设置为`pipeline resolver`和 `APPSYNC_JS` 运行时系统，然后创建解析器。

我们的管道解析器通过先验证电子邮件地址输入，然后将用户保存在系统中来注册用户。我们将电子邮件验证封装在 **validateEmail** 函数中，并将用户保存在 **saveUser** 函数中。首先执行 **validateEmail** 函数，如果电子邮件有效，则执行 **saveUser** 函数。

执行流程如下所示：

1. Mutation.signUp 解析器请求处理程序

1. validateEmail 函数

1. saveUser 函数

1. Mutation.signUp 解析器响应处理程序

由于我们可能在 API 上的其他解析器中重复使用 **validateEmail** 函数，因此，我们希望避免访问 `ctx.args`，因为它们将从一个 GraphQL 字段更改为另一个字段。相反，我们可以使用 `ctx.stash` 存储 `signUp(input: Signup)` 输入字段参数中的电子邮件属性。

替换请求函数和响应函数以更新解析器代码：

```
export function request(ctx) {
    ctx.stash.email = ctx.args.input.email
    return {};
}

export function response(ctx) {
    return ctx.prev.result;
}
```

选择**创建**或**保存**以更新解析器。

## 步骤 2：创建函数
<a name="create-a-function-js"></a>

从管道解析器页面的**函数**部分中，单击**添加函数**，然后单击**创建新函数**。也可以在不通过解析器页面的情况下创建函数；要执行此操作，请在 AWS AppSync控制台中转到 “**函数**” 页面。选择**创建函数**按钮。让我们创建一个函数来检查电子邮件是否有效并来自特定域。如果电子邮件无效，该函数会引发一个错误。否则，它将转发接收到的任何输入。

确保您已创建一个 **NONE** 类型的数据来源。在**数据来源名称**列表中选择该数据来源。对于**函数名称**，请输入 `validateEmail`。在**函数代码**区域中，使用以下代码片段覆盖所有内容：

```
import { util } from '@aws-appsync/utils';

export function request(ctx) {
  const { email } = ctx.stash;
  const valid = util.matches(
    '^[a-zA-Z0-9_.+-]+@(?:(?:[a-zA-Z0-9-]+\.)?[a-zA-Z]+\.)?(myvaliddomain)\.com',
    email
  );
  if (!valid) {
    util.error(`"${email}" is not a valid email.`);
  }

  return { payload: { email } };
}

export function response(ctx) {
  return ctx.result;
}
```

检查您的输入，然后选择**创建**。我们刚刚创建了 **validateEmail** 函数。重复这些步骤以创建具有以下代码的 **saveUser** 函数（为了简单起见，我们使用 **NONE** 数据来源，并假设在函数执行后已将用户保存在系统中）：

```
import { util } from '@aws-appsync/utils';

export function request(ctx) {
  return ctx.prev.result;
}

export function response(ctx) {
  ctx.result.id = util.autoId();
  return ctx.result;
}
```

我们刚刚创建了 **saveUser** 函数。

## 步骤 3：将函数添加到管线解析器
<a name="adding-a-function-to-a-pipeline-resolver-js"></a>

我们的函数应该已自动添加到刚刚创建的管道解析器中。如果情况并非如此，或者您通过**函数**页面创建了函数，您可以再次单击 `signUp` 解析器页面上的**添加函数**以附加这些函数。将 **validateEmail** 和 **saveUser** 函数添加到解析器中。**validateEmail** 函数应放在 **saveUser** 函数之前。在添加更多函数时，您可以使用**上移**和**下移**选项重新排列函数的执行顺序。检查您的更改，然后选择**保存**。

## 步骤 4：运行查询
<a name="running-a-query-js"></a>

在 AWS AppSync 控制台中，转到 “**查询**” 页面。在资源管理器中，确保您正在使用变更。如果不是，请在下拉列表中选择`Mutation`，然后选择 `+`。输入以下查询：

```
mutation {
  signUp(input: {email: "nadia@myvaliddomain.com", username: "nadia"}) {
    id
    username
  }
}
```

它应返回如下内容：

```
{
  "data": {
    "signUp": {
      "id": "256b6cc2-4694-46f4-a55e-8cb14cc5d7fc",
      "username": "nadia"
    }
  }
}
```

我们已成功注册用户，并使用管道解析器验证了输入电子邮件。

# 创建基本查询（VTL）
<a name="configuring-resolvers"></a>

**注意**  
我们现在主要支持 APPSYNC\$1JS 运行时系统及其文档。请考虑使用 APPSYNC\$1JS 运行时系统和[此处](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)的指南。

GraphQL 解析器将类型的架构中的字段连接到数据来源。解析器是满足请求的机制。 AWS AppSync 无需编写任何代码，即可自动创建和连接架构中的解析器，或者创建架构并从现有表连接解析器。

 AWS AppSync 用于将 GraphQL 表达式 JavaScript 转换为数据源可以使用的格式的解析器。或者，可以使用 [Apache Velocity 模板语言 (VTL)](https://velocity.apache.org/engine/2.0/vtl-reference.html) 编写映射模板，以将 GraphQL 表达式转换为数据来源可使用的格式。

本节说明了如何使用 VTL 配置解析器。关于编写解析器的入门教程式编程指南可以在解析器[映射模板编程指南中找到，编程](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide)时可用的帮助工具可以在[解析器](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference)映射模板上下文参考中找到。 AWS AppSync 还具有内置的测试和调试流程，您可以在从头开始编辑或创作时使用这些流程。有关更多信息，请参阅[测试和调试解析器](test-debug-resolvers.md#aws-appsync-test-debug-resolvers)。

我们建议您在尝试使用任何上述教程之前先遵循本指南。

在本节中，我们将介绍如何创建解析器，为变更添加解析器以及使用高级配置。

## 创建您的第一个解析器
<a name="create-your-first-resolver"></a>

按照前面几节中的示例，第一步是为 `Query` 类型创建一个解析器。

------
#### [ Console ]

1. 登录 AWS 管理控制台 并打开[AppSync 控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**APIs 控制面板**中，选择你的 GraphQL API。

   1. 在**侧边栏**中，选择**架构**。

1. 在页面右侧，具有一个名为**解析器**的窗口。该框包含页面左侧的**架构**窗口中定义的类型和字段列表。您可以将解析器附加到字段。例如，在 **Query** 类型下面，选择 `getTodos` 字段旁边的**附加**。

1. 在**创建解析器**页面上，选择您在[附加数据来源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)指南中创建的数据来源。在**配置映射模板**窗口中，您可以使用右侧的下拉列表选择通用请求和响应映射模板，也可以编写自己的映射模板。
**注意**  
请求映射模板与响应映射模板的配对称为单位解析器。单位解析器通常用于执行机械性的操作；我们建议仅将它们用于具有少量数据来源的单一操作。对于更复杂的操作，我们建议使用管道解析器，该解析器按顺序对多个数据来源执行多个操作。  
有关请求映射模板和响应映射模板之间的差异的更多信息，请参阅[单位解析器](https://docs.aws.amazon.com//appsync/latest/devguide/resolver-mapping-template-reference-overview.html#unit-resolvers)。  
有关使用管道解析器的更多信息，请参阅[管道解析器](pipeline-resolvers.md#aws-appsync-pipeline-resolvers)。

1. 对于常见用例， AWS AppSync 控制台内置了模板，您可以使用这些模板从数据源获取项目（例如，所有项目查询、个人查询等）。例如，对于[设计您的架构](designing-your-schema.md#aws-appsync-designing-your-schema)中的简单架构版本（`getTodos` 没有分页），用于列出项目的请求映射模板如下所示：

   ```
   {
       "version" : "2017-02-28",
       "operation" : "Scan"
   }
   ```

1. 您始终需要为请求提供响应映射模板。控制台为列表提供的默认模板具有以下传递值：

   ```
   $util.toJson($ctx.result.items)
   ```

   此示例中，项目列表的 `context` 对象（别名为 `$ctx`）的格式为 `$context.result.items`。如果您的 GraphQL 操作返回一个项目，它将是 `$context.result`。 AWS AppSync 为常用操作提供帮助程序函数，如之前列出的 `$util.toJson` 函数，以保证响应格式正确。有关完整的函数列表，请参阅[解析器映射模板实用程序参考](resolver-util-reference.md#aws-appsync-resolver-mapping-template-util-reference)。

1. 选择**保存解析器**。

------
#### [ API ]

1. 调用 [https://docs.aws.amazon.com/appsync/latest/APIReference/API_CreateResolver.html](https://docs.aws.amazon.com/appsync/latest/APIReference/API_CreateResolver.html) API 以创建一个解析器对象。

1. 您可以调用 [https://docs.aws.amazon.com/appsync/latest/APIReference/API_UpdateResolver.html](https://docs.aws.amazon.com/appsync/latest/APIReference/API_UpdateResolver.html) API 以修改解析器的字段。

------
#### [ CLI ]

1. 运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html) 命令以创建解析器。

   您需要为该特定命令键入 6 个参数：

   1. 您的 API 的 `api-id`。

   1. 您要在架构中修改的类型的 `type-name`。在控制台示例中，这是 `Query`。

   1. 您要在类型中修改的字段的 `field-name`。在控制台示例中，这是 `getTodos`。

   1. 您在[附加数据来源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)指南中创建的数据来源的 `data-source-name`。

   1. `request-mapping-template`，这是请求的正文。在控制台示例中，这是：

      ```
      {
          "version" : "2017-02-28",
          "operation" : "Scan"
      }
      ```

   1. `response-mapping-template`，这是响应的正文。在控制台示例中，这是：

      ```
      $util.toJson($ctx.result.items)
      ```

   示例命令可能如下所示：

   ```
   aws appsync create-resolver --api-id abcdefghijklmnopqrstuvwxyz --type-name Query --field-name getTodos --data-source-name TodoTable --request-mapping-template "{ "version" : "2017-02-28", "operation" : "Scan", }" --response-mapping-template ""$"util.toJson("$"ctx.result.items)"
   ```

   将在 CLI 中返回输出。示例如下：

   ```
   {
       "resolver": {
           "kind": "UNIT",
           "dataSourceName": "TodoTable",
           "requestMappingTemplate": "{ version : 2017-02-28, operation : Scan, }",
           "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Query/resolvers/getTodos",
           "typeName": "Query",
           "fieldName": "getTodos",
           "responseMappingTemplate": "$util.toJson($ctx.result.items)"
       }
   }
   ```

1. 要修改解析器的字段 and/or 映射模板，请运行[https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-resolver.html)命令。

   除了 `api-id` 参数以外，`create-resolver` 命令中使用的参数将由 `update-resolver` 命令中的新值覆盖。

------

## 为变更添加解析器
<a name="adding-a-resolver-for-mutations"></a>

下一步是为您的 `Mutation` 类型创建一个解析器。

------
#### [ Console ]

1. 登录 AWS 管理控制台 并打开[AppSync 控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**APIs 控制面板**中，选择你的 GraphQL API。

   1. 在**侧边栏**中，选择**架构**。

1. 在 **Mutation** 类型下面，选择 `addTodo` 字段旁边的**附加**。

1. 在**创建解析器**页面上，选择您在[附加数据来源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)指南中创建的数据来源。

1. 在**配置映射模板**窗口中，您需要修改请求模板，因为这是一个变更，该操作将新项目添加 DynamoDB 中。使用以下请求映射模板：

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

1. AWS AppSync 自动将`addTodo`字段中定义的参数从 GraphQL 架构转换为 DynamoDB 操作。上一示例使用 `id` 键将记录存储在 DynamoDB 中，该键是从变更参数中作为 `$ctx.args.id` 传递的。您传递的所有其他字段使用 `$util.dynamodb.toMapValuesJson($ctx.args)` 自动映射到 DynamoDB 属性。

   对于此解析器，使用以下响应映射模板：

   ```
   $util.toJson($ctx.result)
   ```

   AWS AppSync 还支持用于编辑解析器的测试和调试工作流程。您可在调用之前使用模拟 `context` 对象查看模板经过转换的值。还可在运行查询时选择以交互方式查看对数据来源的完整请求执行过程。有关更多信息，请参阅[测试和调试解析器](test-debug-resolvers.md#aws-appsync-test-debug-resolvers)和[监控和日志记录](monitoring.md#aws-appsync-monitoring)。

1. 选择**保存解析器**。

------
#### [ API ]

您也可以使用 “[创建您的第一个解析器](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver)” 部分中的命令以及本节中的参数详细信息来执行此操作。 APIs 

------
#### [ CLI ]

您也可以在 CLI 中使用[创建您的第一个解析器](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver)一节中的命令以及本节中的参数详细信息执行该操作。

------

此时，如果您不使用高级解析器，您可以开始使用 GraphQL API，如[使用 API](using-your-api.md#aws-appsync-using-your-api) 中所述。

## 高级解析器
<a name="advanced-resolvers"></a>

如果您按照[设计您的架构](designing-your-schema.md#aws-appsync-designing-your-schema)的“高级”一节进行操作，并构建一个示例架构以执行分页扫描，请将以下请求模板用于 `getTodos` 字段：

```
{
    "version" : "2017-02-28",
    "operation" : "Scan",
    "limit": $util.defaultIfNull(${ctx.args.limit}, 20),
    "nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.nextToken, null))
}
```

对于这个分页使用案例，响应映射不只是简单的传递，因为它必须包含*光标*（这样客户端才知道下次从哪一页开始）以及结果集。映射模板如下所示：

```
{
    "todos": $util.toJson($context.result.items),
    "nextToken": $util.toJson($context.result.nextToken)
}
```

以上响应映射模板中的字段必须与 `TodoConnection` 类型中定义的字段匹配。

如果存在以下关系：您具有 `Comments` 表并且要解析 `Todo` 类型（返回 `[Comment]` 类型）的 Comments 字段，您可以使用映射模板以对第二个表运行查询。为此，您必须已为 `Comments` 表创建了一个数据来源，如[附加数据来源](attaching-a-data-source.md#aws-appsync-getting-started-build-a-schema-from-scratch)中所述。

**注意**  
我们对第二个表使用查询操作仅用于说明目的。您可以对 DynamoDB 使用其他操作。此外，您可以从其他数据源（例如 AWS Lambda 或 Amazon S OpenSearch ervice）提取数据，因为该关系由您的 GraphQL 架构控制。

------
#### [ Console ]

1. 登录 AWS 管理控制台 并打开[AppSync 控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**APIs 控制面板**中，选择你的 GraphQL API。

   1. 在**侧边栏**中，选择**架构**。

1. 在 **Todo** 类型下面，选择 `comments` 字段旁边的**附加**。

1. 在**创建解析器**页面上，选择您的 **Comments** 表数据来源。快速入门指南中的 **Comments** 表的默认名称是 `AppSyncCommentTable`，但它可能会根据您指定的名称而有所不同。

1. 将以下代码片段添加到您的请求映射模板中：

   ```
   {
       "version": "2017-02-28",
       "operation": "Query",
       "index": "todoid-index",
       "query": {
           "expression": "todoid = :todoid",
           "expressionValues": {
               ":todoid": {
                   "S": $util.toJson($context.source.id)
               }
           }
       }
   }
   ```

1. `context.source` 会引用当前被解析的字段的父对象。在本示例中，`source.id` 指单个 `Todo` 对象，之后它会被用于查询表达式。

   您可以如下所示使用传递响应映射模板：

   ```
   $util.toJson($ctx.result.items)
   ```

1. 选择**保存解析器**。

1. 最后，返回到控制台中的**架构**页面，将一个解析器附加到 `addComment` 字段，并指定 `Comments` 表的数据来源。在此例中请求映射模板只是简单的 `PutItem`，它具有作为参数注释的特定 `todoid`，但您可以使用 `$utils.autoId()` 实用程序来为如下所示注释创建唯一的排序键：

   ```
   {
       "version": "2017-02-28",
       "operation": "PutItem",
       "key": {
           "todoid": { "S": $util.toJson($context.arguments.todoid) },
           "commentid": { "S": "$util.autoId()" }
       },
       "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
   }
   ```

   如下所示使用传递响应模板：

   ```
   $util.toJson($ctx.result)
   ```

------
#### [ API ]

您也可以使用 “[创建您的第一个解析器](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver)” 部分中的命令以及本节中的参数详细信息来执行此操作。 APIs 

------
#### [ CLI ]

您也可以在 CLI 中使用[创建您的第一个解析器](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver)一节中的命令以及本节中的参数详细信息执行该操作。

------

# 使用直接 Lambda 解析器（VTL）禁用 VTL 映射模板
<a name="direct-lambda-reference"></a>

**注意**  
我们现在主要支持 APPSYNC\$1JS 运行时系统及其文档。请考虑使用 APPSYNC\$1JS 运行时系统和[此处](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)的指南。

使用直接 Lambda 解析器，您可以在使用数据源时避开 VTL 映射模板的使用。 AWS Lambda AWS AppSync 可以为您的 Lambda 函数提供默认负载，以及从 Lambda 函数的响应到 GraphQL 类型的默认转换。您可以选择提供请求模板、响应模板，或者两者都不提供， AWS AppSync 并将相应地进行处理。

要详细了解 AWS AppSync 提供的默认请求负载和响应转换，请参阅 [Direct Lambda 解析器](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers)参考。有关设置 AWS Lambda 数据源和设置 IAM 信任策略的更多信息，请参阅[附加数据源](attaching-a-data-source.md)。

## 配置直接 Lambda 解析器
<a name="direct-lambda-reference-resolvers"></a>

以下几节说明了如何附加 Lambda 数据来源，并将 Lambda 解析器添加到您的字段中。

### 添加 Lambda 数据来源
<a name="direct-lambda-datasource"></a>

您必须先添加 Lambda 数据来源，然后才能激活直接 Lambda 解析器。

------
#### [ Console ]

1. 登录 AWS 管理控制台 并打开[AppSync控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**APIs 控制面板**中，选择你的 GraphQL API。

   1. 在**侧边栏**中，选择**数据来源**。

1. 选择**创建数据来源**。

   1. 对于**数据来源名称**，输入您的数据来源的名称，例如 **myFunction**。

   1. 对于**数据来源类型**，选择 **AWS Lambda 函数**。

   1. 对于**区域**，选择相应的区域。

   1. 对于**函数 ARN**，从下拉列表中选择 Lambda 函数。您可以搜索函数名称，或手动输入要使用的函数的 ARN。

   1. 创建新的 IAM 角色（建议），或者选择具有 `lambda:invokeFunction` IAM 权限的现有角色。现有角色需要具有一个信任策略，如[附加数据来源](attaching-a-data-source.md)一节中所述。

      以下是一个示例 IAM 策略，该策略具有对资源执行操作所需的权限：

------
#### [ JSON ]

****  

      ```
      { 
           "Version":"2012-10-17",		 	 	  
           "Statement": [ 
               { 
                   "Effect": "Allow", 
                   "Action": [ "lambda:invokeFunction" ], 
                   "Resource": [ 
                       "arn:aws:lambda:us-west-2:123456789012:function:myFunction", 
                       "arn:aws:lambda:us-west-2:123456789012:function:myFunction:*" 
                   ] 
               } 
           ] 
       }
      ```

------

1. 选择**创建**按钮。

------
#### [ CLI ]

1. 运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-data-source.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-data-source.html) 命令以创建数据来源对象。

   您需要为该特定命令键入 4 个参数：

   1. 您的 API 的 `api-id`。

   1. 您的数据来源的 `name`。在控制台示例中，这是**数据来源名称**。

   1. 数据来源的 `type`。在控制台示例中，这是 **AWS Lambda 函数**。

   1. `lambda-config`，即控制台示例中的**函数 ARN**。
**注意**  
必须配置其他参数（例如 `Region`），但这些参数通常默认为您的 CLI 配置值。

   示例命令可能如下所示：

   ```
   aws appsync create-data-source --api-id abcdefghijklmnopqrstuvwxyz --name myFunction --type AWS_LAMBDA --lambda-config lambdaFunctionArn=arn:aws:lambda:us-west-2:102847592837:function:appsync-lambda-example
   ```

   将在 CLI 中返回输出。示例如下：

   ```
   {
       "dataSource": {
           "dataSourceArn": "arn:aws:appsync:us-west-2:102847592837:apis/abcdefghijklmnopqrstuvwxyz/datasources/myFunction",
           "type": "AWS_LAMBDA",
           "name": "myFunction",
           "lambdaConfig": {
               "lambdaFunctionArn": "arn:aws:lambda:us-west-2:102847592837:function:appsync-lambda-example"
           }
       }
   }
   ```

1. 要修改数据来源的属性，请运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-data-source.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-data-source.html) 命令。

   除了 `api-id` 参数以外，`create-data-source` 命令中使用的参数将由 `update-data-source` 命令中的新值覆盖。

------

### 激活直接 Lambda 解析器
<a name="direct-lambda-enable-templates"></a>

创建 Lambda 数据源并设置相应的 IAM 角色 AWS AppSync 以允许调用该函数后，您可以将其链接到解析器或管道函数。

------
#### [ Console ]

1. 登录 AWS 管理控制台 并打开[AppSync控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**APIs 控制面板**中，选择你的 GraphQL API。

   1. 在**侧边栏**中，选择**架构**。

1. 在**解析器**窗口中，选择一个字段或操作，然后选择**附加**按钮。

1. 在**创建新解析器**页面中，从下拉列表中选择 Lambda 函数。

1. 要使用直接 Lambda 解析器，请确认在**配置映射模板**部分中禁用了请求和响应映射模板。

1. 选择**保存解析器**按钮。

------
#### [ CLI ]
+ 运行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html) 命令以创建解析器。

  您需要为该特定命令键入 6 个参数：

  1. 您的 API 的 `api-id`。

  1. 架构中的类型的 `type-name`。

  1. 架构中的字段的 `field-name`。

  1. `data-source-name` 或您的 Lambda 函数名称。

  1. `request-mapping-template`，这是请求的正文。在控制台示例中，已将其禁用：

     ```
     " "
     ```

  1. `response-mapping-template`，这是响应的正文。在控制台示例中，也已将其禁用：

     ```
     " "
     ```

  示例命令可能如下所示：

  ```
  aws appsync create-resolver --api-id abcdefghijklmnopqrstuvwxyz --type-name Subscription --field-name onCreateTodo --data-source-name LambdaTest --request-mapping-template " " --response-mapping-template " "
  ```

  将在 CLI 中返回输出。示例如下：

  ```
  {
      "resolver": {
          "resolverArn": "arn:aws:appsync:us-west-2:102847592837:apis/abcdefghijklmnopqrstuvwxyz/types/Subscription/resolvers/onCreateTodo",
          "typeName": "Subscription",
          "kind": "UNIT",
          "fieldName": "onCreateTodo",
          "dataSourceName": "LambdaTest"
      }
  }
  ```

------

在您禁用映射模板时，将在 AWS AppSync中出现一些其他行为：
+ 禁用映射模板 AWS AppSync 即表示您接受 Di [rect Lambda](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers) 解析器参考中指定的默认数据转换。
+ 通过禁用请求映射模板，您的 Lambda 数据来源将接收包含整个[上下文](resolver-context-reference.md)对象的负载。
+ 通过禁用响应映射模板，将转换您的 Lambda 调用结果，具体取决于请求映射模板版本或是否还禁用了请求映射模板。

# 在 AWS AppSync (VTL) 中测试和调试解析器
<a name="test-debug-resolvers"></a>

**注意**  
我们现在主要支持 APPSYNC\$1JS 运行时系统及其文档。请考虑使用 APPSYNC\$1JS 运行时系统和[此处](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)的指南。

AWS AppSync 针对数据源对 GraphQL 字段执行解析器。正如[解析器映射模板概述](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview)中所述，解析器使用模板语言与数据来源进行通信。这样，您就可以在与数据来源通信之前和之后自定义行为并应用逻辑和条件。有关编写解析器的入门教程风格的编程指南，请参阅[解析器映射模板编程指南](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide)。

为了帮助开发者编写、测试和调试这些解析器， AWS AppSync 控制台还提供了一些工具，用于创建 GraphQL 请求和响应，并将模拟数据传递给各个字段解析器。此外，您还可以在 AWS AppSync 控制台中执行查询、变更和订阅，并查看来自 Amazon CloudWatch 的整个请求的详细日志流。其中包括从数据来源获得的结果。

## 使用模拟数据进行测试
<a name="testing-with-mock-data"></a>

在调用 GraphQL 解析器时，它包含一个 `context` 对象，其中包含有关请求的信息。其中包括来自客户端的参数、身份信息以及 GraphQL 父字段的数据。它还包含来自数据来源的结果，可以在响应模板中使用这些结果。有关此结构的更多信息以及在编程时可用的帮助程序实用程序，请参阅[解析器映射模板上下文参考](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference)。

在编写或编辑解析器时，您可以将*模拟* 或*测试上下文* 对象传递到控制台编辑器中。这使您能够查看请求和响应模板如何评估，而不必针对数据来源实际运行。例如，您可以传递测试 `firstname: Shaggy` 参数，观察在您的模板代码中使用 `$ctx.args.firstname` 时如何评估。您还可以测试任何实用程序帮助程序（例如 `$util.autoId()` 或 `util.time.nowISO8601()`）的评估。

### 测试解析器
<a name="test-a-resolver"></a>

此示例将使用 AWS AppSync 控制台测试解析器。

1. 登录 AWS 管理控制台 并打开[AppSync控制台](https://console.aws.amazon.com/appsync/)。

   1. 在**APIs 控制面板**中，选择你的 GraphQL API。

   1. 在**侧边栏**中，选择**架构**。

1. 如果您尚未在类型下面的字段旁边选择**附加**以添加解析器，请执行该操作。

   有关如何构建完整解析器的更多信息，请参阅[配置解析器](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html)。

   否则，选择已位于字段中的解析器。

1. 在**编辑解析器**页面顶部，选择**选择测试上下文**，然后选择**创建新上下文**。

1. 选择一个示例上下文对象，或者在下面的**执行上下文**窗口中手动填充 JSON。

1. 输入**测试上下文名称**。

1. 选择**保存**按钮。

1. 在**编辑解析器**页面顶部，选择**运行测试**。

举一个更实际的例子，假设您具有一个存储 GraphQL 类型 `Dog` 的应用程序，该应用程序自动为对象生成 ID 并将其存储在 Amazon DynamoDB 中。您还希望通过 GraphQL 变更参数写入一些值，并仅允许特定用户查看响应。下面显示了架构的外观：

```
type Dog {
  breed: String
  color: String
}

type Mutation {
  addDog(firstname: String, age: Int): Dog
}
```

在您为 `addDog` 变更添加解析器时，您可以填充上下文对象，如以下示例中所示。以下代码拥有 `name` 和 `age` 客户端的参数，以及 `identity` 对象中填充的 `username`：

```
{
    "arguments" : {
        "firstname": "Shaggy",
        "age": 4
    },
    "source" : {},
    "result" : {
        "breed" : "Miniature Schnauzer",
        "color" : "black_grey"
    },
    "identity": {
        "sub" : "uuid",
        "issuer" : " https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
        "username" : "Nadia",
        "claims" : { },
        "sourceIp" :[  "x.x.x.x" ],
        "defaultAuthStrategy" : "ALLOW"
    }
}
```

您可以使用以下请求和响应映射模板测试此内容：

 **请求模板** 

```
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        "id" : { "S" : "$util.autoId()" }
    },
    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
```

 **响应模板** 

```
#if ($context.identity.username == "Nadia")
  $util.toJson($ctx.result)
#else
  $util.unauthorized()
#end
```

经过评估的模板拥有您的测试上下文对象的数据，以及 `$util.autoId()` 生成的值。此外，如果您要将 `username` 更改为除 `Nadia` 之外的值，将不会返回结果，因为授权检查将失败。有关精细访问控制的更多信息，请参阅[授权使用案例](security-authorization-use-cases.md#aws-appsync-security-authorization-use-cases)。

### 使用 AWS AppSync's 测试映射模板 APIs
<a name="testing-with-appsync-api"></a>

您可以通过 `EvaluateMappingTemplate` API 命令使用模拟数据远程测试您的映射模板。要开始使用该命令，请确保您已将 `appsync:evaluateMappingTemplate` 权限添加到您的策略中。例如：

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appsync:evaluateMappingTemplate",
            "Resource": "arn:aws:appsync:us-east-1:111122223333:*"
        }
    ]
}
```

------

您可以使用[AWS CLI](https://aws.amazon.com/cli/)或来利用该命令[AWS SDKs](https://aws.amazon.com/tools/)。例如，以上一节中的`Dog`架构及其 request/response 映射模板为例。通过在本地工作站上使用 CLI，将请求模板保存到名为 `request.vtl` 的文件中，然后将 `context` 对象保存到名为 `context.json` 的文件中。从 Shell 中，运行以下命令：

```
aws appsync evaluate-mapping-template --template file://request.vtl --context file://context.json
```

该命令返回以下响应：

```
{
  "evaluationResult": "{\n    \"version\" : \"2017-02-28\",\n    \"operation\" : \"PutItem\",\n    \"key\" : {\n        \"id\" : { \"S\" : \"afcb4c85-49f8-40de-8f2b-248949176456\" }\n    },\n    \"attributeValues\" : {\"firstname\":{\"S\":\"Shaggy\"},\"age\":{\"N\":4}}\n}\n"
}
```

`evaluationResult` 包含使用提供的 `context` 测试您提供的模板的结果。您也可以使用测试您的模板 AWS SDKs。以下是使用适用于 JavaScript V2 的 AWS SDK 的示例：

```
const AWS = require('aws-sdk')
const client = new AWS.AppSync({ region: 'us-east-2' })

const template = fs.readFileSync('./request.vtl', 'utf8')
const context = fs.readFileSync('./context.json', 'utf8')

client
  .evaluateMappingTemplate({ template, context })
  .promise()
  .then((data) => console.log(data))
```

通过使用 SDK，您可以轻松合并常用的测试套件中的测试以验证模板行为。我们建议使用 [Jest 测试框架](https://jestjs.io/)创建测试，但任何测试套件都有效。以下代码片段显示假设的验证运行。请注意，我们希望评估响应是有效的 JSON ，因此，我们使用 `JSON.parse` 从字符串响应中检索 JSON：

```
const AWS = require('aws-sdk')
const fs = require('fs')
const client = new AWS.AppSync({ region: 'us-east-2' })

test('request correctly calls DynamoDB', async () => {
  const template = fs.readFileSync('./request.vtl', 'utf8')
  const context = fs.readFileSync('./context.json', 'utf8')
  const contextJSON = JSON.parse(context)
  
  const response = await client.evaluateMappingTemplate({ template, context }).promise()
  const result = JSON.parse(response.evaluationResult)
  
  expect(result.key.id.S).toBeDefined()
  expect(result.attributeValues.firstname.S).toEqual(contextJSON.arguments.firstname)
})
```

 这会产生以下结果：

```
Ran all test suites.
> jest

PASS ./index.test.js
✓ request correctly calls DynamoDB (543 ms)

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.511 s, estimated 2 s
```

## 调试实时查询
<a name="debugging-a-live-query"></a>

除了调试生产应用程序的 end-to-end测试和日志记录之外，别无选择。 AWS AppSync 允许您使用 Amazon 记录错误和完整的请求详情 CloudWatch。此外，您可以使用 AWS AppSync 控制台测试 GraphQL 查询、突变和订阅，并将每个请求的实时日志数据流回查询编辑器进行实时调试。对于订阅而言，日志显示连接时间信息。

要执行此操作，您需要提前启用 Amazon CloudWatch 日志，如[监控和日志](monitoring.md#aws-appsync-monitoring)中所述。接下来，在 AWS AppSync 控制台中选择 “**查询**” 选项卡，然后输入有效的 GraphQL 查询。在右下部分中，单击并拖动**日志**窗口以打开“日志”视图。在页面顶部，选择“播放”箭头图标运行您的 GraphQL 查询。片刻之后，此操作的完整请求和响应日志将流式传输到控制台的这一部分，之后您可以在控制台中进行查看。

# 在 AWS AppSync (VTL) 中配置和使用管道解析器
<a name="pipeline-resolvers"></a>

**注意**  
我们现在主要支持 APPSYNC\$1JS 运行时系统及其文档。请考虑使用 APPSYNC\$1JS 运行时系统和[此处](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)的指南。

AWS AppSync 在 GraphQL 字段上执行解析器。在某些情况下，应用程序需要执行多个操作以解析单个 GraphQL 字段。通过使用管道解析器，开发人员现在可以编写称为“函数”的操作并按顺序执行它们。例如，管道解析器对于需要在获取字段数据之前执行授权检查的应用程序非常有用。

管道解析器由**之前** 映射模板、**之后** 映射模板和一组函数组成。每个函数具有对数据来源执行的**请求**映射模板和**响应**映射模板。由于管道解析器将执行委托给函数列表，因此它不会链接到任何数据来源。单位解析器和函数是对数据来源执行操作的基元。有关更多信息，请参阅[解析器映射模板概述](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview)。

## 步骤 1：创建管线解析器
<a name="create-a-pipeline-resolver"></a>

在 AWS AppSync 控制台中，转到 “**架构**” 页面。

保存以下架构：

```
schema {
    query: Query
    mutation: Mutation
}

type Mutation {
    signUp(input: Signup): User
}

type Query {
    getUser(id: ID!): User
}

input Signup {
    username: String!
    email: String!
}

type User {
    id: ID!
    username: String
    email: AWSEmail
}
```

我们将一个管道解析器连接到 **Mutation** 类型的 **signUp** 字段。在右侧的 **Mutation** 类型中，选择 `signUp` 变更字段旁边的**附加**。在“创建解析器”页面上，单击**操作**，然后单击**更新运行时**。依次选择`Pipeline Resolver`、`VTL` 和**更新**。该页面现在应显示三个部分：**之前映射模板**文本区域、**函数**部分和**之后映射模板**文本区域。

我们的管道解析器通过先验证电子邮件地址输入，然后将用户保存在系统中来注册用户。我们将电子邮件验证封装在 **validateEmail** 函数中，并将用户保存在 **saveUser** 函数中。首先执行 **validateEmail** 函数，如果电子邮件有效，则执行 **saveUser** 函数。

执行流将如下所示：

1. Mutation.signUp 解析器请求映射模板

1. validateEmail 函数

1. saveUser 函数

1. Mutation.signUp 解析器响应映射模板

由于我们可能在 API 上的其他解析器中重复使用 **validateEmail** 函数，因此，我们希望避免访问 `$ctx.args`，因为它们将从一个 GraphQL 字段更改为另一个字段。相反，我们可以使用 `$ctx.stash` 存储 `signUp(input: Signup)` 输入字段参数中的电子邮件属性。

**之前**映射模板：

```
## store email input field into a generic email key
$util.qr($ctx.stash.put("email", $ctx.args.input.email))
{}
```

控制台提供一个我们将使用的默认传递**之后**映射模板：

```
$util.toJson($ctx.result)
```

选择**创建**或**保存**以更新解析器。

## 步骤 2：创建函数
<a name="create-a-function"></a>

从管道解析器页面的**函数**部分中，单击**添加函数**，然后单击**创建新函数**。也可以在不通过解析器页面的情况下创建函数；要执行此操作，请在 AWS AppSync控制台中转到 “**函数**” 页面。选择**创建函数**按钮。让我们创建一个函数来检查电子邮件是否有效并来自特定域。如果电子邮件无效，该函数会引发一个错误。否则，它将转发接收到的任何输入。

在新函数页面上，选择**操作**，然后选择**更新运行时**。选择 `VTL`，然后选择**更新**。确保您已创建一个 **NONE** 类型的数据来源。在**数据来源名称**列表中选择该数据来源。对于**函数名称**，请输入 `validateEmail`。在**函数代码**区域中，使用以下代码片段覆盖所有内容：

```
#set($valid = $util.matches("^[a-zA-Z0-9_.+-]+@(?:(?:[a-zA-Z0-9-]+\.)?[a-zA-Z]+\.)?(myvaliddomain)\.com", $ctx.stash.email))
#if (!$valid)
    $util.error("$ctx.stash.email is not a valid email.")
#end
{
    "payload": { "email": $util.toJson(${ctx.stash.email}) }
}
```

将其粘贴到响应映射模板中：

```
$util.toJson($ctx.result)
```

检查您的更改，然后选择**创建**。我们刚刚创建了 **validateEmail** 函数。重复这些步骤以创建具有以下请求和响应映射模板的 **saveUser** 函数（为了简单起见，我们使用 **NONE** 数据来源，并假设在函数执行后已将用户保存在系统中）：

请求映射模板：

```
## $ctx.prev.result contains the signup input values. We could have also
## used $ctx.args.input.
{
    "payload": $util.toJson($ctx.prev.result)
}
```

响应映射模板：

```
## an id is required so let's add a unique random identifier to the output
$util.qr($ctx.result.put("id", $util.autoId()))
$util.toJson($ctx.result)
```

我们刚刚创建了 **saveUser** 函数。

## 步骤 3：将函数添加到管线解析器
<a name="adding-a-function-to-a-pipeline-resolver"></a>

我们的函数应该已自动添加到刚刚创建的管道解析器中。如果情况并非如此，或者您通过**函数**页面创建了函数，您可以单击解析器页面上的**添加函数**以附加这些函数。将 **validateEmail** 和 **saveUser** 函数添加到解析器中。**validateEmail** 函数应放在 **saveUser** 函数之前。在添加更多函数时，您可以使用**上移**和**下移**选项重新排列函数的执行顺序。检查您的更改，然后选择**保存**。

## 步骤 4：执行查询
<a name="executing-a-query"></a>

在 AWS AppSync 控制台中，转到 “**查询**” 页面。在资源管理器中，确保您正在使用变更。如果不是，请在下拉列表中选择`Mutation`，然后选择 `+`。输入以下查询：

```
mutation {
  signUp(input: {
    email: "nadia@myvaliddomain.com"
    username: "nadia"
  }) {
    id
    email
  }
}
```

它应返回如下内容：

```
{
  "data": {
    "signUp": {
      "id": "256b6cc2-4694-46f4-a55e-8cb14cc5d7fc",
      "email": "nadia@myvaliddomain.com"
    }
  }
}
```

我们已成功注册用户，并使用管道解析器验证了输入电子邮件。要遵循有关管道解析器的更完整的教程，您可以转到[教程：管道解析器](tutorial-pipeline-resolvers.md#aws-appsync-tutorial-pipeline-resolvers) 

# 在 AWS CDK 中使用 AWS AppSync API
<a name="using-your-api"></a>

**提示**  
在使用 CDK 之前，我们建议您查看 CDK 的[官方文档](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html)以及 [CD](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 AWS AppSync  
我们还建议确保 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 和 [NPM](https://docs.npmjs.com/) 安装在您的系统上正常工作。

在本节中，我们将创建一个简单的 CDK 应用程序，该应用程序可以在 DynamoDB 表中添加和获取项目。这是一个快速入门示例，使用了 “[设计架构](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html)”、“[附加数据源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)” 和 “[配置解析器” () JavaScript](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html) 部分中的一些代码。

## 设置 CDK 项目
<a name="Setting-up-a-cdk-project"></a>

**警告**  
根据您的环境，这些步骤可能不完全准确。我们假设您的系统已安装必要的实用程序、与 AWS 服务接口的方法以及适当的配置。

第一步是安装 AWS CDK。在 CLI 中，您可以输入以下命令：

```
npm install -g aws-cdk
```

接下来，您需要创建一个项目目录，然后导航到该目录。用于创建和导航到目录的一组示例命令是：

```
mkdir example-cdk-app
cd example-cdk-app
```

接下来，您需要创建一个应用程序。我们的服务主要使用 TypeScript. 在您的项目目录中，输入以下命令：

```
cdk init app --language typescript
```

在您执行该操作时，将安装 CDK 应用程序及其初始化文件：

![\[Terminal output showing Git repository initialization and npm install completion.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-init-app-example.png)


您的项目结构可能如下所示：

![\[Project directory structure showing folders and files for an example CDK app.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-init-directories.png)


您会注意到我们具有几个重要目录：
+ `bin`：初始 bin 文件将创建应用程序。我们在本指南中不会对其进行修改。
+ `lib`：lib 目录包含您的堆栈文件。您可以将堆栈文件视为单独的执行单元。构造将位于我们的堆栈文件中。基本上，这些是部署应用程序 CloudFormation 时将启动的服务的资源。这是我们完成大部分编码的位置。
+ `node_modules`：该目录由 NPM 创建，并包含您使用 `npm` 命令安装的所有包依赖项。

我们的初始堆栈文件可能包含如下内容：

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
// import * as sqs from 'aws-cdk-lib/aws-sqs';

export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here

    // example resource
    // const queue = new sqs.Queue(this, 'ExampleCdkAppQueue', {
    //   visibilityTimeout: cdk.Duration.seconds(300)
    // });
  }
}
```

这是在我们的应用程序中创建堆栈的样板代码。该示例中的大部分代码都位于该类的范围内。

要验证您的堆栈文件是否位于应用程序的目录中，请在终端中运行以下命令：

```
cdk ls
```

应该会显示您的堆栈列表。如果没有显示，您可能需要再次执行这些步骤，或者查看官方文档以获得帮助。

如果要在部署之前构建代码更改，您始终可以在终端中运行以下命令：

```
npm run build
```

要在部署之前查看更改，请运行以下命令：

```
cdk diff
```

在将代码添加到堆栈文件之前，我们将执行引导。通过进行引导，我们可以在部署应用程序之前为 CDK 预置资源。可以在[此处](https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html)找到有关该过程的更多信息。要创建引导，请运行以下命令：

```
cdk bootstrap aws://ACCOUNT-NUMBER/REGION
```

**提示**  
该步骤要求在您的账户中具有多个 IAM 权限。如果您没有这些权限，将拒绝您的引导。如果发生这种情况，您可能必须删除引导导致的不完整资源，例如，引导生成的 S3 存储桶。

引导将启动多个资源。最终消息将如下所示：

![\[Terminal output showing successful bootstrapping of an AWS environment.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-init-bootstrap-final.png)


该操作对每个账户的每个区域执行一次，因此，您无需经常这样做。引导程序的主要资源是 CloudFormation 堆栈和 Amazon S3 存储桶。

Amazon S3 存储桶用于存储文件和 IAM 角色，这些角色授予执行部署所需的权限。所需的资源是在一个名为引导 CloudFormation 堆栈的堆栈中定义的，该堆栈通常被命名为`CDKToolkit`。与任何 CloudFormation 堆栈一样，它在部署后会显示在 CloudFormation 控制台中：

![\[CDKToolkit stack with CREATE_COMPLETE status in CloudFormation console.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-init-bootstrap-cfn-console.png)


存储桶也是如此：

![\[S3 bucket details showing name, region, access settings, and creation date.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-init-bootstrap-bucket-console.png)


要在堆栈文件中导入所需的服务，我们可以使用以下命令：

```
npm install aws-cdk-lib # V2 command
```

**提示**  
如果您在使用 V2 时遇到问题，您可以使用 V1 命令安装各个库：  

```
npm install @aws-cdk/aws-appsync @aws-cdk/aws-dynamodb
```
我们不建议这样做，因为 V1 已被弃用。

## 实施 CDK 项目 - 架构
<a name="implementing-a-cdk-project-schema"></a>

我们现在可以开始实施代码了。首先，我们必须创建架构。您只需在应用程序中创建一个 `.graphql` 文件即可：

```
mkdir schema
touch schema.graphql
```

在我们的示例中，我们包含一个名为 `schema` 的顶级目录，其中包含 `schema.graphql`：

![\[File structure showing a schema folder containing schema.graphql file.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-schema-directory.png)


在我们的架构中，让我们包含一个简单的示例：

```
input CreatePostInput {
    title: String
    content: String
}

type Post {
    id: ID!
    title: String
    content: String
}

type Mutation {
    createPost(input: CreatePostInput!): Post
}

type Query {
    getPost: [Post]
}
```

回到我们的堆栈文件，我们需要确保定义了以下 import 指令：

```
import * as cdk from 'aws-cdk-lib';
import * as appsync from 'aws-cdk-lib/aws-appsync';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';
```

在类中，我们将添加代码以创建 GraphQL API 并将其连接到 `schema.graphql` 文件：

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    // makes a GraphQL API
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });
  }
}
```

我们还会添加一些代码以输出 GraphQL URL、API 密钥和区域：

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    // Makes a GraphQL API construct
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });

    // Prints out URL
    new cdk.CfnOutput(this, "GraphQLAPIURL", {
      value: api.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "GraphQLAPIKey", {
      value: api.apiKey || ''
    });

    // Prints out the stack region to the terminal
    new cdk.CfnOutput(this, "Stack Region", {
      value: this.region
    });
  }
}
```

此时，再次部署我们的应用程序：

```
cdk deploy
```

结果如下所示：

![\[Deployment output showing ExampleCdkAppStack details, including GraphQL API URL and stack region.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-schema.png)


看来我们的示例成功了，但让我们检查一下 AWS AppSync 控制台以确认：

![\[GraphQL interface showing successful API request with response data displayed.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-schema-result-1.png)


看来已创建了我们的 API。现在，我们将检查附加到 API 的架构：

![\[GraphQL schema defining CreatePostInput, Post type, Mutation, and Query operations.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-schema-result-2.png)


这似乎与我们的架构代码匹配，因此，它是成功的。从元数据角度确认这一点的另一种方法是查看 CloudFormation 堆栈：

![\[CloudFormation stack showing ExampleCdkAppStack update complete and CDKToolkit creation complete.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-schema-result-3.png)


当我们部署 CDK 应用程序时，它会启动引导程序等资源。 CloudFormation 我们的应用程序中的每个堆栈都与一个堆 CloudFormation 栈以 1:1 的比分映射。如果您回到堆栈代码，就会发现堆栈名称是从类名称 `ExampleCdkAppStack` 中获取的。您可以看到它创建的资源，这些资源也符合 GraphQL API 构造中的命名约定：

![\[Expanded view of post-apis resource showing Schema, DefaultApiKey, and CDKMetadata.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-schema-result-4.png)


## 实施 CDK 项目 - 数据来源
<a name="implementing-a-cdk-project-data-source"></a>

接下来，我们需要添加数据来源。我们的示例使用 DynamoDB 表。在堆栈类中，我们添加一些代码以创建新的表：

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Makes a GraphQL API construct
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });

    //creates a DDB table
    const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
      partitionKey: {
        name: 'id',
        type: dynamodb.AttributeType.STRING,
      },
    });

    // Prints out URL
    new cdk.CfnOutput(this, "GraphQLAPIURL", {
      value: api.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "GraphQLAPIKey", {
      value: api.apiKey || ''
    });

    // Prints out the stack region to the terminal
    new cdk.CfnOutput(this, "Stack Region", {
      value: this.region
    });
  }
}
```

此时，让我们再次部署：

```
cdk deploy
```

我们应该检查 DynamoDB 控制台是否有新的表：

![\[DynamoDB console showing ExampleCdkAppStack-poststable as Active with Provisioned capacity.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-ddb-result-1.png)


我们的堆栈名称是正确的，并且表名称与代码匹配。如果我们再次检查 CloudFormation 堆栈，我们现在将看到新表：

![\[Expanded view of a logical ID in CloudFormation showing post-apis, posts-table, and CDKMetadata.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-ddb-result-2.png)


## 实施 CDK 项目 - 解析器
<a name="implementing-a-cdk-project-resolver"></a>

该示例将使用两个解析器：一个用于查询表，另一个用于在表中添加数据。由于我们使用管道解析器，因此，我们需要声明两个管道解析器，在每个解析器中具有一个函数。在查询中，我们添加以下代码：

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Makes a GraphQL API construct
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });

    //creates a DDB table
    const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
      partitionKey: {
        name: 'id',
        type: dynamodb.AttributeType.STRING,
      },
    });

    // Creates a function for query
    const add_func = new appsync.AppsyncFunction(this, 'func-get-post', {
      name: 'get_posts_func_1',
      api,
      dataSource: api.addDynamoDbDataSource('table-for-posts', add_ddb_table),
      code: appsync.Code.fromInline(`
          export function request(ctx) {
          return { operation: 'Scan' };
          }

          export function response(ctx) {
          return ctx.result.items;
          }
  `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
    });

    // Creates a function for mutation
    const add_func_2 = new appsync.AppsyncFunction(this, 'func-add-post', {
      name: 'add_posts_func_1',
      api,
      dataSource: api.addDynamoDbDataSource('table-for-posts-2', add_ddb_table),
      code: appsync.Code.fromInline(`
          export function request(ctx) {
            return {
            operation: 'PutItem',
            key: util.dynamodb.toMapValues({id: util.autoId()}),
            attributeValues: util.dynamodb.toMapValues(ctx.args.input),
            };
          }

          export function response(ctx) {
            return ctx.result;
          }
      `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
    });

    // Adds a pipeline resolver with the get function
    new appsync.Resolver(this, 'pipeline-resolver-get-posts', {
      api,
      typeName: 'Query',
      fieldName: 'getPost',
      code: appsync.Code.fromInline(`
          export function request(ctx) {
          return {};
          }

          export function response(ctx) {
          return ctx.prev.result;
          }
  `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
      pipelineConfig: [add_func],
    });

    // Adds a pipeline resolver with the create function
    new appsync.Resolver(this, 'pipeline-resolver-create-posts', {
      api,
      typeName: 'Mutation',
      fieldName: 'createPost',
      code: appsync.Code.fromInline(`
          export function request(ctx) {
          return {};
          }

          export function response(ctx) {
          return ctx.prev.result;
          }
  `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
      pipelineConfig: [add_func_2],
    });

    // Prints out URL
    new cdk.CfnOutput(this, "GraphQLAPIURL", {
      value: api.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "GraphQLAPIKey", {
      value: api.apiKey || ''
    });

    // Prints out the stack region to the terminal
    new cdk.CfnOutput(this, "Stack Region", {
      value: this.region
    });
  }
}
```

在该代码片段中，我们添加一个名为 `pipeline-resolver-create-posts` 的管道解析器，并将一个名为 `func-add-post` 的函数附加到该解析器。这是将 `Posts` 添加到表中的代码。另一个管道解析器命名为 `pipeline-resolver-get-posts`，并具有一个名为 `func-get-post` 的函数，该函数检索添加到表中的 `Posts`。

我们将部署它以将其添加到 AWS AppSync 服务中：

```
cdk deploy
```

让我们检查一下 AWS AppSync 控制台，看看它们是否已连接到我们的 GraphQL API：

![\[GraphQL API schema showing mutation and query fields with Pipeline resolvers.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-1.png)


看来是正确的。在代码中，这两个解析器都附加到我们创建的 GraphQL API（由解析器和函数中存在的 `api` 属性值表示）。在 GraphQL API 中，我们将解析器附加到的字段也是在属性中指定的（由每个解析器中的 `typename` 和 `fieldname` 属性定义）。

让我们看看解析器内容是否正确，从 `pipeline-resolver-get-posts` 开始：

![\[Code snippet showing request and response functions in a resolver, with an arrow pointing to them.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-2.png)


之前和之后处理程序与 `code` 属性值匹配。我们还可以看到一个名为 `add_posts_func_1` 的函数，它与我们在解析器中附加的函数的名称匹配。

我们看一下该函数的代码内容：

![\[Function code showing request and response methods for a PutItem operation.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-3.png)


这与 `add_posts_func_1` 函数的 `code` 属性匹配。已成功上传我们的查询，因此，让我们检查一下该查询：

![\[Resolver code with request and response functions, and a get_posts_func_1 function listed below.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-4.png)


这些也与代码匹配。如果我们看一下 `get_posts_func_1`：

![\[Code snippet showing two exported functions: request returning 'Scan' operation and response returning items.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-5.png)


一切似乎准备就绪。要从元数据角度确认这一点，我们可以再次在 CloudFormation 中检查堆栈：

![\[List of logical IDs for AWS resources including API, table, functions, and pipelines.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-6.png)


现在，我们需要执行一些请求以测试该代码。

## 实施 CDK 项目 - 请求
<a name="implementing-a-cdk-project-requests"></a>

为了在 AWS AppSync 控制台中测试我们的应用程序，我们做了一个查询和一个变更：

![\[GraphQL code snippet showing a query to get post details and a mutation to create a post.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-request-1.png)


`MyMutation` 包含具有 `createPost` 和 `1970-01-01T12:30:00.000Z` 参数的 `first post` 操作。它返回我们传入的 `date` 和 `title` 以及自动生成的 `id` 值。运行该变更将产生以下结果：

```
{
  "data": {
    "createPost": {
      "date": "1970-01-01T12:30:00.000Z",
      "id": "4dc1c2dd-0aa3-4055-9eca-7c140062ada2",
      "title": "first post"
    }
  }
}
```

如果快速检查 DynamoDB 表，我们可以在扫描时在该表中看到我们的条目：

![\[DynamoDB table entry showing id, date, and title fields for a single item.\]](http://docs.aws.amazon.com/zh_cn/appsync/latest/devguide/images/cdk-code-request-2.png)


回到 AWS AppSync 控制台，如果我们运行查询来检索它`Post`，我们会得到以下结果：

```
{
  "data": {
    "getPost": [
      {
        "id": "9f62c4dd-49d5-48d5-b835-143284c72fe0",
        "date": "1970-01-01T12:30:00.000Z",
        "title": "first post"
      }
    ]
  }
}
```