

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

# 在 Amazon AppSync 中配置解析器
配置 Amazon AppSync 解析器

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

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

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

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

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

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

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

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

**Topics**
+ [

# 创建基本查询 (JavaScript)
](configuring-resolvers-js.md)
+ [

# 创建基本查询（VTL）
](configuring-resolvers.md)

# 创建基本查询 (JavaScript)


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

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

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

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

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

**注意**  
本指南假设您已创建架构并至少具有一个查询或变更。如果您要获取订阅（实时数据），请参阅[本](https://docs.amazonaws.cn/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]
}
```

## 创建基本查询解析器


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

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

1. 登录 Amazon Web Services 管理控制台 并打开[AppSync控制台](https://console.amazonaws.cn/appsync/)。

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

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

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

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

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

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

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

1. 在**编辑解析器**页面上，具有一个名为**解析器代码**的代码编辑器，可用于实施解析器处理程序和响应的逻辑（预备步骤和后续步骤）。有关更多信息，请参阅[JavaScript解析器概述](https://docs.amazonaws.cn/appsync/latest/devguide/resolver-reference-overview-js.html)。
**注意**  
在我们的示例中，我们直接将请求保留空白，并将响应设置为从[上下文](https://docs.amazonaws.cn/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.amazonaws.cn/appsync/latest/devguide/resolver-context-reference-js.html)对象中。然后，运行列表中的下一个函数；如果是最后一个函数，则将其传递给后续步骤响应处理程序。
**注意**  
在我们的示例中，我们将一个解析器附加到 `getPost`，它从数据来源获取 `Post` 对象列表。我们的请求函数将从我们的表中请求数据，表将其响应传递给上下文 (ctx)，然后响应将在上下文中返回结果。 Amazon AppSync的优势在于它与其他服务的互连性。 Amazon 由于我们使用的是 DynamoDB，因此，我们具有[一组操作](https://docs.amazonaws.cn/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.amazonaws.cn//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan](https://docs.amazonaws.cn//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan) 操作（请参阅[此处](https://docs.amazonaws.cn/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.amazonaws.cn/cli/latest/reference/appsync/create-function.html)` 命令为管道解析器创建一个函数。

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

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

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

  1. `data-source-name` 或函数使用的数据来源名称。它必须已创建并链接到 Amazon 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.amazonaws.cn/cdk/v2/guide/home.html)以及 [CD](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 Amazon AppSync  
下面列出的步骤仅显示用于添加特定资源的一般代码片段示例。这**并不**意味着，它是您的生产代码中的有效解决方案。我们还假设您已具有正常工作的应用程序。

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

1. 服务导入指令

1. 架构代码

1. 数据来源生成器

1. 函数代码

1. 解析器代码

从[设计您的架构](https://docs.amazonaws.cn/appsync/latest/devguide/designing-your-schema.html)和[附加数据来源](https://docs.amazonaws.cn/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'
```

**注意**  
在前面的章节中，我们只说明了如何导入 Amazon AppSync 构造。在实际代码中，您必须导入更多服务才能运行应用程序。在我们的示例中，如果我们要创建一个非常简单的 CDK 应用程序，我们至少要导入该 Amazon 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.amazonaws.cn/cdk/v2/guide/migrating-v2.html) 页面。
`import * as appsync from 'aws-cdk-lib/aws-appsync';`：它导入 [Amazon AppSync 服务](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)。
`import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';`：它导入 [DynamoDB 服务](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb-readme.html)。
`import { Construct } from 'constructs';`：我们需要使用该指令以定义根[构造](https://docs.amazonaws.cn/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`，属性包含实际函数详细信息。我们在属性中包含：  
 Amazon AppSync 控制台中将出现的函数 (`get_posts_func_1`)。`name`
我们以前创建的 GraphQL API (`add_api`)。
数据来源；我们在其中将数据来源链接到 GraphQL API 值，然后将其附加到函数。我们获取创建的表 (`add_ddb_table`)，并使用 `GraphqlApi` 方法之一 ([https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options)) 将其附加到 GraphQL API (`add_api`)。ID 值 (`table-for-posts`) 是 Amazon AppSync 控制台中的数据来源的名称。有关源特定的方法列表，请参阅以下页面：  
[ DynamoDbDataSource ](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.DynamoDbDataSource.html) 
 [ EventBridgeDataSource ](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.EventBridgeDataSource.html) 
 [ HttpDataSource ](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.HttpDataSource.html) 
 [ LambdaDataSource ](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.LambdaDataSource.html) 
 [ NoneDataSource ](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.NoneDataSource.html) 
 [ OpenSearchDataSource ](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.OpenSearchDataSource.html) 
 [ RdsDataSource ](https://docs.amazonaws.cn/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`) 的引用。

------

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

## 创建基本变更解析器


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

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

1. 登录 Amazon Web Services 管理控制台 并打开[AppSync控制台](https://console.amazonaws.cn/appsync/)。

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

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

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

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

1. 您可以为该 API 启用[缓存](https://docs.amazonaws.cn/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.amazonaws.cn//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem](https://docs.amazonaws.cn//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem) 命令，这是内置的 DynamoDB 操作（请参阅[此处](https://docs.amazonaws.cn/amazondynamodb/latest/developerguide/getting-started-step-2.html)或[此处](https://docs.amazonaws.cn/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.WritingData)的示例）。`PutItem` 命令获取分区 `key` 值（由 `util.autoid()` 自动生成）以及来自上下文参数输入的 `attributes`（这些是在请求中传递的值），以将 `Post` 对象添加到我们的 DynamoDB 表中。`key` 是 `id`，`attributes` 是 `date` 和 `title` 字段参数。它们通过 [https://docs.amazonaws.cn//appsync/latest/devguide/dynamodb-helpers-in-util-dynamodb-js.html#utility-helpers-in-toMap-js](https://docs.amazonaws.cn//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.amazonaws.cn/cli/latest/reference/appsync/create-function.html)` 命令为管道解析器创建一个函数。

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

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

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

  1. `data-source-name` 或函数使用的数据来源名称。它必须已创建并链接到 Amazon 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.amazonaws.cn/cdk/v2/guide/home.html)以及 [CD](https://docs.amazonaws.cn/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html) K 参考资料。 Amazon 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` 添加到表中的情况。在数据源中，我们在 Amazon AppSync 控制台中与表 (`add_ddb_table`) 建立了新的关联，`table-for-posts-2`因为该`addDynamoDbDataSource`方法需要它。请记住，这个新的关联仍在使用我们之前创建的同一个表，但是我们现在在 Amazon AppSync 控制台中有两个与它的连接：一个用于查询 as`table-for-posts`，另一个用于变异为`table-for-posts-2`。代码进行了更改以添加 `Post`，方法是自动生成其 `id` 值，并接受客户端输入以用于其余字段。  
在解析器中，我们将 id 值更改为 `pipeline-resolver-create-posts` 以反映我们将 `Posts` 添加到表中的情况。为了反映架构中的变更，类型名称更改为 `Mutation`，名称更改为 `createPost`。管道配置设置为我们的新变更函数 `add_func_2`。

------

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

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

## 高级解析器


如果您按照[设计您的架构](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` 条目。发出的下一个请求执行完全相同的操作，但从紧靠第一个查询后面的偏移开始。请记住，这些类型的请求是按顺序完成的，而不是并行完成的。

# 在 Amazon AppSync () JavaScript 中测试和调试解析器
测试和调试解析器 () JavaScript

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

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

## 使用模拟数据进行测试


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

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

### 测试解析器


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

1. 登录 Amazon Web Services 管理控制台 并打开[AppSync控制台](https://console.amazonaws.cn/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
}
```

你可以编写一个 Amazon AppSync 函数并将其添加到你的`addDog`解析器中来处理突变。要测试您的 Amazon 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"
    }
}
```

您可以使用以下代码测试您的 Amazon 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测试请求和响应处理 Amazon AppSync程序 APIs


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

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

****  

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

------

您可以使用[Amazon CLI](https://www.amazonaws.cn/cli/)或来利用该命令[Amazon SDKs](https://www.amazonaws.cn/tools/)。例如，以上一节中的`Dog`架构及其 Amazon 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
```

## 调试实时查询


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

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

# 在 Amazon AppSync () JavaScript 中配置和使用管道解析器
配置和使用管道解析器 () JavaScript

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

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

## 步骤 1：创建管线解析器


在 Amazon 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：创建函数


从管道解析器页面的**函数**部分中，单击**添加函数**，然后单击**创建新函数**。也可以在不通过解析器页面的情况下创建函数；要执行此操作，请在 Amazon 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：将函数添加到管线解析器


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

## 步骤 4：运行查询


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

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

它应返回如下内容：

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

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

# 创建基本查询（VTL）


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

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

 Amazon 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)映射模板上下文参考中找到。 Amazon AppSync 还具有内置的测试和调试流程，您可以在从头开始编辑或创作时使用这些流程。有关更多信息，请参阅[测试和调试解析器](test-debug-resolvers.md#aws-appsync-test-debug-resolvers)。

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

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

## 创建您的第一个解析器


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

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

1. 登录 Amazon Web Services 管理控制台 并打开[AppSync 控制台](https://console.amazonaws.cn/appsync/)。

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

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

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

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

1. 对于常见用例， Amazon 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`。 Amazon AppSync 为常用操作提供帮助程序函数，如之前列出的 `$util.toJson` 函数，以保证响应格式正确。有关完整的函数列表，请参阅[解析器映射模板实用程序参考](resolver-util-reference.md#aws-appsync-resolver-mapping-template-util-reference)。

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

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

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

1. 您可以调用 [https://docs.amazonaws.cn/appsync/latest/APIReference/API_UpdateResolver.html](https://docs.amazonaws.cn/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.amazonaws.cn/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` 命令中的新值覆盖。

------

## 为变更添加解析器


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

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

1. 登录 Amazon Web Services 管理控制台 并打开[AppSync 控制台](https://console.amazonaws.cn/appsync/)。

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

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

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

1. 在**创建解析器**页面上，选择您在[附加数据来源](https://docs.amazonaws.cn/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. Amazon AppSync 自动将`addTodo`字段中定义的参数从 GraphQL 架构转换为 DynamoDB 操作。上一示例使用 `id` 键将记录存储在 DynamoDB 中，该键是从变更参数中作为 `$ctx.args.id` 传递的。您传递的所有其他字段使用 `$util.dynamodb.toMapValuesJson($ctx.args)` 自动映射到 DynamoDB 属性。

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

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

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

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

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

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

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

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

------

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

## 高级解析器


如果您按照[设计您的架构](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 使用其他操作。此外，您可以从其他数据源（例如 Amazon Lambda 或 Amazon S OpenSearch ervice）提取数据，因为该关系由您的 GraphQL 架构控制。

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

1. 登录 Amazon Web Services 管理控制台 并打开[AppSync 控制台](https://console.amazonaws.cn/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.amazonaws.cn/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver)” 部分中的命令以及本节中的参数详细信息来执行此操作。 APIs 

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

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

------

# 使用直接 Lambda 解析器（VTL）禁用 VTL 映射模板


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

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

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

## 配置直接 Lambda 解析器


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

### 添加 Lambda 数据来源


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

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

1. 登录 Amazon Web Services 管理控制台 并打开[AppSync控制台](https://console.amazonaws.cn/appsync/)。

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

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

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

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

   1. 对于**数据来源类型**，选择 **Amazon 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`。在控制台示例中，这是 **Amazon 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 解析器


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

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

1. 登录 Amazon Web Services 管理控制台 并打开[AppSync控制台](https://console.amazonaws.cn/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"
      }
  }
  ```

------

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

# 在 Amazon AppSync (VTL) 中测试和调试解析器
测试和调试解析器（VTL）

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

Amazon 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)。

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

## 使用模拟数据进行测试


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

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

### 测试解析器


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

1. 登录 Amazon Web Services 管理控制台 并打开[AppSync控制台](https://console.amazonaws.cn/appsync/)。

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

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

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

   有关如何构建完整解析器的更多信息，请参阅[配置解析器](https://docs.amazonaws.cn/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)。

### 使用 Amazon AppSync's 测试映射模板 APIs


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

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

****  

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

------

您可以使用[Amazon CLI](https://www.amazonaws.cn/cli/)或来利用该命令[Amazon SDKs](https://www.amazonaws.cn/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` 测试您提供的模板的结果。您也可以使用测试您的模板 Amazon SDKs。以下是使用适用于 JavaScript V2 的 Amazon 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
```

## 调试实时查询


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

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

# 在 Amazon AppSync (VTL) 中配置和使用管道解析器
配置和使用管线解析器（VTL）

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

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

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

## 步骤 1：创建管线解析器


在 Amazon 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：创建函数


从管道解析器页面的**函数**部分中，单击**添加函数**，然后单击**创建新函数**。也可以在不通过解析器页面的情况下创建函数；要执行此操作，请在 Amazon 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：将函数添加到管线解析器


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

## 步骤 4：执行查询


在 Amazon 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) 