

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 DynamoDB 解析程式建立簡單的貼文應用程式
<a name="tutorial-dynamodb-resolvers"></a>

**注意**  
我們現在主要支援 APPSYNC\$1JS 執行期及其文件。請考慮[在此處](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)使用 APPSYNC\$1JS 執行期及其指南。

本教學課程說明如何將自己的 Amazon DynamoDB 資料表帶到 AWS AppSync，並將其連接到 GraphQL API。

您可以讓 AWS AppSync 代表您佈建 DynamoDB 資源。或者，如果您願意，您可以透過建立資料來源和解析程式來將現有的資料表連接到 GraphQL 結構描述。在這兩種情況下，您將能夠透過 GraphQL 陳述式讀取和寫入 DynamoDB 資料庫，以及訂閱即時資料。

有您必須完成的特定的組態步驟，才能讓 GraphQL 陳述式轉譯到 DynamoDB 操作，以及讓回應轉譯回 GraphQL。本教學課程概述透過幾個真實世界案例和資料存取模式的組態程序。

## 設定 DynamoDB 資料表
<a name="setting-up-your-ddb-tables"></a>

若要開始本教學課程，您必須先遵循下列步驟來佈建 AWS 資源。

1. 在 CLI 中使用下列 AWS CloudFormation 範本佈建 AWS 資源：

   ```
   aws cloudformation create-stack \
       --stack-name AWSAppSyncTutorialForAmazonDynamoDB \
       --template-url https://s3.us-west-2.amazonaws.com/awsappsync/resources/dynamodb/AmazonDynamoDBCFTemplate.yaml \
       --capabilities CAPABILITY_NAMED_IAM
   ```

   或者，您可以在帳戶中 AWS 的美國西部 2 （奧勒岡） 區域啟動下列 CloudFormation 堆疊。

   [https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https://s3.us-west-2.amazonaws.com/awsappsync/resources/dynamodb/AmazonDynamoDBCFTemplate.yaml](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https://s3.us-west-2.amazonaws.com/awsappsync/resources/dynamodb/AmazonDynamoDBCFTemplate.yaml)

   這將會建立下列項目：
   + 稱為 `AppSyncTutorial-Post`的 DynamoDB 資料表，可存放`Post`資料。
   + IAM 角色和相關聯的 IAM 受管政策，以允許 AWS AppSync 與`Post`資料表互動。

1. 要查看有關堆疊和建立的資源的詳細資訊，請執行以下 CLI 命令：

   ```
   aws cloudformation describe-stacks --stack-name AWSAppSyncTutorialForAmazonDynamoDB
   ```

1. 之後若要刪除資源，您可以執行以下項目：

   ```
   aws cloudformation delete-stack --stack-name AWSAppSyncTutorialForAmazonDynamoDB
   ```

## 建立 GraphQL API
<a name="creating-your-graphql-api"></a>

若要在 AWS AppSync 中建立 GraphQL API：

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇**建立 API**。

1. 在**自訂您的 API 或從 Amazon DynamoDB 匯入**視窗下，選擇**從頭建置**。

   1. 選擇相同視窗右側的**開始**。

1. 在 **API 名稱**欄位中，將 API 的名稱設定為 `AWSAppSyncTutorial`。

1. 選擇**建立**。

 AWS AppSync 主控台會使用 API 金鑰身分驗證模式為您建立新的 GraphQL API。您可以使用主控台來設定其他 GraphQL API 和對其執行查詢，以進行此教學的其他部分。

## 定義基本文章 API
<a name="defining-a-basic-post-api"></a>

現在您已建立 an AWS AppSync GraphQL API，您可以設定基本結構描述，以允許基本建立、擷取和刪除文章資料。

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您剛建立的 API。

1. 在**側邊欄中**，選擇**結構描述**。

   1. 在**結構描述**窗格中，使用下列程式碼取代內容：

     ```
     schema {
         query: Query
         mutation: Mutation
     }
     
     type Query {
         getPost(id: ID): Post
     }
     
     type Mutation {
         addPost(
             id: ID!
             author: String!
             title: String!
             content: String!
             url: String!
         ): Post!
     }
     
     type Post {
         id: ID!
         author: String
         title: String
         content: String
         url: String
         ups: Int!
         downs: Int!
         version: Int!
     }
     ```

1. 選擇**儲存**。

這個結構描述會定義 `Post` 類型和操作以新增和取得 `Post` 物件。

## 設定 DynamoDB 資料表的資料來源
<a name="configuring-the-data-source-for-the-ddb-tables"></a>

接著，將結構描述中定義的查詢和變動連結至 `AppSyncTutorial-Post`DynamoDB 資料表。

首先， AWS AppSync 需要注意您的資料表。您可以在 AWS AppSync 中設定資料來源來執行此操作：

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**資料來源**。

1. 選擇 **Create data source (建立資料來源)**。

   1. 對於**資料來源名稱**，在 中輸入 `PostDynamoDBTable`。

   1. 針對**資料來源類型**，選擇 **Amazon DynamoDB 資料表**。

   1. 針對**區域**，選擇 **US-WEST-2**。

   1. 針對**資料表名稱**，選擇 **AppSyncTutorial-Post** DynamoDB 資料表。

   1. 建立新的 IAM 角色 （建議） 或選擇具有 IAM `lambda:invokeFunction` 許可的現有角色。現有角色需要信任政策，如[連接資料來源](attaching-a-data-source.md)一節所述。

      以下是 IAM 政策範例，其具有對資源執行操作所需的許可：

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

****  

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

------

1. 選擇**建立**。

## 設定 addPost 解析程式 (DynamoDB PutItem)
<a name="setting-up-the-addpost-resolver-dynamodb-putitem"></a>

After AWS AppSync 知道 DynamoDB 資料表，您可以透過定義**解析程式**將其連結至個別查詢和變動。您建立的第一個解析程式是`addPost`解析程式，可讓您在 `AppSyncTutorial-Post` DynamoDB 資料表中建立文章。

解析程式具有下列元件：
+ 在 GraphQL 結構描述中要附加解析程式的位置。在這種情況下，您會對 `addPost` 類型上的 `Mutation` 欄位設定解析程式。發起人呼叫 `mutation { addPost(...){...} }` 時會叫用此解析程式。
+ 用於此解析程式的資料來源。在這種情況下，您想要使用先前定義的 `PostDynamoDBTable` 資料來源，如此您可以將項目新增到 `AppSyncTutorial-Post` DynamoDB 資料表。
+ 請求映射範本。請求映射範本的目的是從發起人取得傳入請求，並將其轉換為指示 for AWS AppSync 以對 DynamoDB 執行。
+ 回應映射範本。回應映射範本的任務即是從 DynamoDB 取得回應，並將其轉譯為 GraphQL 期望的項目。如果 DynamoDB 中的資料形狀與 GraphQL 中的 `Post` 類型不同，此功能會很有用，但如果他們的形狀一樣，您只需傳遞資料。

設定解析程式：

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**資料來源**。

1. 選擇 **Create data source (建立資料來源)**。

   1. 對於**資料來源名稱**，在 中輸入 `PostDynamoDBTable`。

   1. 針對**資料來源類型**，選擇 **Amazon DynamoDB 資料表**。

   1. 針對**區域**，選擇 **US-WEST-2**。

   1. 針對**資料表名稱**，選擇 **AppSyncTutorial-Post** DynamoDB 資料表。

   1. 建立新的 IAM 角色 （建議） 或選擇具有 IAM `lambda:invokeFunction` 許可的現有角色。現有角色需要信任政策，如[連接資料來源](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. 選擇**建立**。

1. 選擇 **Schema (結構描述)** 標籤。

1. 在右側的**資料類型**窗格中，尋找**變動**類型的 **addPost** 欄位，然後選擇**連接**。

1. 在**動作功能表中**，選擇**更新執行時間**，然後選擇**單位解析程式 （僅限 VTL)**。

1. 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。

1. 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

   ```
   {
       "version" : "2017-02-28",
       "operation" : "PutItem",
       "key" : {
           "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
       },
       "attributeValues" : {
           "author" : $util.dynamodb.toDynamoDBJson($context.arguments.author),
           "title" : $util.dynamodb.toDynamoDBJson($context.arguments.title),
           "content" : $util.dynamodb.toDynamoDBJson($context.arguments.content),
           "url" : $util.dynamodb.toDynamoDBJson($context.arguments.url),
           "ups" : { "N" : 1 },
           "downs" : { "N" : 0 },
           "version" : { "N" : 1 }
       }
   }
   ```

   **注意：**所有金鑰和屬性值皆有指定的*類型*。例如，您將 `author` 欄位設為 `{ "S" : "${context.arguments.author}" }`。`S` 部分指出 to AWS AppSync 和 DynamoDB 的值將是字串值。會將實際值填入 `author` 引數。同樣地，`version` 欄位是號碼欄位，因為它會將 `N` 用於類型。最後，您也可以初始化 `ups`、`downs` 和 `version` 欄位。

   在本教學課程中，您已指定 GraphQL `ID!`類型，該類型會將插入 DynamoDB 的新項目編製索引，做為 client arguments. AWS AppSync comes 的一部分，其中包含名為 的自動 ID 產生公用程式`$utils.autoId()`，您也可以以 的形式使用`"id" : { "S" : "${$utils.autoId()}" }`。然後，您可以直接將 `id: ID!` 移出 `addPost()` 的結構描述定義，該 ID 便會自動插入。您不會在本教學課程中使用此技術，但您應該將其視為寫入 DynamoDB 資料表時的最佳實務。

   如需映射範本的詳細資訊，請參閱[解析程式映射範本概觀](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview)參考文件。如需 GetItem 要求映射的詳細資訊，請參閱 [GetItem](aws-appsync-resolver-mapping-template-reference-dynamodb-getitem.md) 參考文件。如需有關類型的詳細資訊，請參閱[類型系統 (要求映射)](aws-appsync-resolver-mapping-template-reference-dynamodb-typed-values-request.md) 參考文件。

1. 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

   ```
   $utils.toJson($context.result)
   ```

    **注意：**由於 `AppSyncTutorial-Post` 資料表中的資料形狀正好與 GraphQL 中的 `Post` 類型形狀相符，回應映射範本只需直接傳遞結果。另請注意，此教學課程中的所有範例會使用相同的回應映射範本，因此您只需建立一個檔案。

1. 選擇**儲存**。

### 呼叫 API 以新增文章
<a name="call-the-api-to-add-a-post"></a>

現在已設定解析程式， AWS AppSync 可以將傳入`addPost`的變動轉譯為 DynamoDB PutItem 操作。您現在可以執行變動以將項目放置到資料表中。
+ 選擇 **Queries (查詢)** 標籤。
+ 將以下變動貼到 **Queries (查詢)** 窗格：

  ```
  mutation addPost {
    addPost(
      id: 123
      author: "AUTHORNAME"
      title: "Our first post!"
      content: "This is our first post."
      url: "https://aws.amazon.com/appsync/"
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 新建立文章的結果應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "addPost": {
        "id": "123",
        "author": "AUTHORNAME",
        "title": "Our first post!",
        "content": "This is our first post.",
        "url": "https://aws.amazon.com/appsync/",
        "ups": 1,
        "downs": 0,
        "version": 1
      }
    }
  }
  ```

以下是發生的情況：
+ AWS AppSync 收到`addPost`變動請求。
+ AWS AppSync 接受了請求和請求映射範本，並產生了請求映射文件。此看起來如下：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "PutItem",
      "key" : {
          "id" : { "S" : "123" }
      },
      "attributeValues" : {
          "author": { "S" : "AUTHORNAME" },
          "title": { "S" : "Our first post!" },
          "content": { "S" : "This is our first post." },
          "url": { "S" : "https://aws.amazon.com/appsync/" },
          "ups" : { "N" : 1 },
          "downs" : { "N" : 0 },
          "version" : { "N" : 1 }
      }
  }
  ```
+ AWS AppSync 使用請求映射文件來產生和執行 DynamoDB`PutItem` 請求。
+ AWS AppSync 取得`PutItem`請求的結果，並將其轉換回 GraphQL 類型。

  ```
  {
      "id" : "123",
      "author": "AUTHORNAME",
      "title": "Our first post!",
      "content": "This is our first post.",
      "url": "https://aws.amazon.com/appsync/",
      "ups" : 1,
      "downs" : 0,
      "version" : 1
  }
  ```
+ 透過回應映射文件來進行傳遞，這可讓其以原狀進行傳遞。
+ 傳回在 GraphQL 回應中新建立的物件。

## 設定 getPost 解析程式 (DynamoDB GetItem)
<a name="setting-up-the-getpost-resolver-ddb-getitem"></a>

現在，您可以將資料新增至 `AppSyncTutorial-Post`DynamoDB 資料表，您需要設定`getPost`查詢，以便從`AppSyncTutorial-Post`資料表擷取該資料。若要執行此作業，您可以設定另一個解析程式。
+ 選擇 **Schema (結構描述)** 標籤。
+ 在右側的**資料類型**窗格中，尋找**查詢**類型的 **getPost** 欄位，然後選擇**連接**。
+ 在**動作功能表中**，選擇**更新執行時間**，然後選擇**單位解析程式 （僅限 VTL)**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "GetItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
      }
  }
  ```
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  $utils.toJson($context.result)
  ```
+ 選擇**儲存**。

### 呼叫 API 以取得文章
<a name="call-the-api-to-get-a-post"></a>

現在已設定解析程式， AWS AppSync 知道如何將傳入`getPost`查詢轉譯為 DynamoDB`GetItem` 操作。您現在可以執行查詢，擷取您稍早建立的貼文。
+ 選擇 **Queries (查詢)** 標籤。
+ 在 **Queries (查詢)** 窗格中，貼入下面內容：

  ```
  query getPost {
    getPost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 從 DynamoDB 擷取的文章應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "getPost": {
        "id": "123",
        "author": "AUTHORNAME",
        "title": "Our first post!",
        "content": "This is our first post.",
        "url": "https://aws.amazon.com/appsync/",
        "ups": 1,
        "downs": 0,
        "version": 1
      }
    }
  }
  ```

以下是發生的情況：
+ AWS AppSync 收到`getPost`查詢請求。
+ AWS AppSync 接受了請求和請求映射範本，並產生了請求映射文件。此看起來如下：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "GetItem",
      "key" : {
          "id" : { "S" : "123" }
      }
  }
  ```
+ AWS AppSync 使用請求映射文件來產生和執行 DynamoDB GetItem 請求。
+ AWS AppSync 取得`GetItem`請求的結果，並將其轉換回 GraphQL 類型。

  ```
  {
      "id" : "123",
      "author": "AUTHORNAME",
      "title": "Our first post!",
      "content": "This is our first post.",
      "url": "https://aws.amazon.com/appsync/",
      "ups" : 1,
      "downs" : 0,
      "version" : 1
  }
  ```
+ 透過回應映射文件來進行傳遞，這可讓其以原狀進行傳遞。
+ 在回應中傳回擷取的物件。

或者，請採用下列範例：

```
query getPost {
  getPost(id:123) {
    id
    author
    title
  }
}
```

如果您的`getPost`查詢只需要 `id`、 `author`和 `title`，您可以將請求映射範本變更為使用投影表達式，以僅指定您希望從 DynamoDB 資料表傳輸的屬性，以避免從 DynamoDB 傳輸不必要的資料 AWS AppSync。例如，請求映射範本可能看起來像下面的程式碼片段：

```
{
    "version" : "2017-02-28",
    "operation" : "GetItem",
    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
    },
    "projection" : {
     "expression" : "#author, id, title",
     "expressionNames" : { "#author" : "author"}
    }
}
```

## 建立 updatePost Mutation (DynamoDB UpdateItem)
<a name="create-an-updatepost-mutation-ddb-updateitem"></a>

到目前為止，您可以在 DynamoDB 中建立和擷取`Post`物件。接下來，您會設定新的變動，讓我們能夠更新物件。您可以使用 UpdateItem DynamoDB 操作來執行此作業。
+ 選擇 **Schema (結構描述)** 標籤。
+ 修改 **Schema (結構描述)** 窗格中的 `Mutation` 類型來新增 `updatePost` 變動，如下所示：

  ```
  type Mutation {
      updatePost(
          id: ID!,
          author: String!,
          title: String!,
          content: String!,
          url: String!
      ): Post
      addPost(
          author: String!
          title: String!
          content: String!
          url: String!
      ): Post!
  }
  ```
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**變動**類型上新建立的 **updatePost** 欄位，然後選擇**連接**。
+ 在**動作功能表中**，選擇**更新執行時間**，然後選擇**單位解析程式 （僅限 VTL)**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "SET author = :author, title = :title, content = :content, #url = :url ADD version :one",
          "expressionNames": {
              "#url" : "url"
          },
          "expressionValues": {
              ":author" : $util.dynamodb.toDynamoDBJson($context.arguments.author),
              ":title" : $util.dynamodb.toDynamoDBJson($context.arguments.title),
              ":content" : $util.dynamodb.toDynamoDBJson($context.arguments.content),
              ":url" : $util.dynamodb.toDynamoDBJson($context.arguments.url),
              ":one" : { "N": 1 }
          }
      }
  }
  ```

   **注意：**此解析程式正在使用 DynamoDB UpdateItem，這與 PutItem 操作明顯不同。您只是要求 DynamoDB 更新特定屬性，而不是撰寫整個項目。這是使用 DynamoDB Update Expressions 完成。表達式本身會在 `expression` 區段中的 `update` 欄位中指定。其要求設定 `author`、`title`、`content` 以及 url 屬性，然後遞增 `version` 欄位。要使用的值不會出現在表達式本身；表達式的預留位置名稱開頭為冒號，其會在 `expressionValues` 欄位中加以定義。最後，DynamoDB 保留了無法在 中顯示的單字`expression`。例如，由於 `url` 是保留字，因此若要更新 `url` 欄位，您可以使用名稱預留位置，並在 `expressionNames` 欄位中定義他們。

  如需 `UpdateItem` 請求映射的詳細資訊，請參閱 [UpdateItem](aws-appsync-resolver-mapping-template-reference-dynamodb-updateitem.md) 參考文件。如需有關如何撰寫更新表達式的詳細資訊，請參閱 [DynamoDB UpdateExpressions 文件](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html)。
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  $utils.toJson($context.result)
  ```

### 呼叫 API 以更新文章
<a name="call-the-api-to-update-a-post"></a>

現在已設定解析程式， AWS AppSync 知道如何將傳入`update`變動轉換為 DynamoDB`Update` 操作。您現在可以執行變動，以更新您之前撰寫的項目。
+ 選擇 **Queries (查詢)** 標籤。
+ 將以下變動貼到 **Queries (查詢)** 窗格。您也必須將 `id` 引數更新為您先前記下的值。

  ```
  mutation updatePost {
    updatePost(
      id:"123"
      author: "A new author"
      title: "An updated author!"
      content: "Now with updated content!"
      url: "https://aws.amazon.com/appsync/"
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ DynamoDB 中更新的文章應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "updatePost": {
        "id": "123",
        "author": "A new author",
        "title": "An updated author!",
        "content": "Now with updated content!",
        "url": "https://aws.amazon.com/appsync/",
        "ups": 1,
        "downs": 0,
        "version": 2
      }
    }
  }
  ```

在此範例中， `ups`和 `downs` 欄位並未修改，因為請求映射範本並未 ask AWS AppSync 和 DynamoDB 對這些欄位執行任何動作。此外， `version` 欄位以 1 遞增，因為您要求 AWS AppSync 和 DynamoDB 將 1 新增至 `version` 欄位。

## 修改 updatePost 解析程式 (DynamoDB UpdateItem)
<a name="modifying-the-updatepost-resolver-dynamodb-updateitem"></a>

這對於 `updatePost` 變動而言是一個好的開始，但有兩個主要的問題：
+ 如果您只想更新單一欄位，您必須更新所有欄位。
+ 如果兩個人同時修改物件，您便可能會失去資訊。

為了解決這些問題，您將會修改 `updatePost` 變動，使其僅修改請求中指定的引數，然後將條件新增到 `UpdateItem` 操作。

1. 選擇 **Schema (結構描述)** 標籤。

1. 在 **Schema (結構描述)** 窗格中，修改 `Mutation` 類型中的 `updatePost` 欄位，以便從 `author`、`title`、`content` 及 `url` 引數中移除驚嘆號，並請確保 `id` 欄位維持原狀。這會使它們變成可選引數。此外，新增必要 `expectedVersion` 引數。

   ```
   type Mutation {
       updatePost(
           id: ID!,
           author: String,
           title: String,
           content: String,
           url: String,
           expectedVersion: Int!
       ): Post
       addPost(
           author: String!
           title: String!
           content: String!
           url: String!
       ): Post!
   }
   ```

1. 選擇**儲存**。

1. 在右側的**資料類型**窗格中，尋找 **Mutation** 類型的 **updatePost** 欄位。

1. 選擇 **PostDynamoDBTable** 以開啟現有的解析程式。

1. 在 **Configure the request mapping template (設定要求映射範本)** 中修改要求映射範本，如下所示：

   ```
   {
       "version" : "2017-02-28",
       "operation" : "UpdateItem",
       "key" : {
           "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
       },
   
       ## Set up some space to keep track of things you're updating **
       #set( $expNames  = {} )
       #set( $expValues = {} )
       #set( $expSet = {} )
       #set( $expAdd = {} )
       #set( $expRemove = [] )
   
       ## Increment "version" by 1 **
       $!{expAdd.put("version", ":one")}
       $!{expValues.put(":one", { "N" : 1 })}
   
       ## Iterate through each argument, skipping "id" and "expectedVersion" **
       #foreach( $entry in $context.arguments.entrySet() )
           #if( $entry.key != "id" && $entry.key != "expectedVersion" )
               #if( (!$entry.value) && ("$!{entry.value}" == "") )
                   ## If the argument is set to "null", then remove that attribute from the item in DynamoDB **
   
                   #set( $discard = ${expRemove.add("#${entry.key}")} )
                   $!{expNames.put("#${entry.key}", "$entry.key")}
               #else
                   ## Otherwise set (or update) the attribute on the item in DynamoDB **
   
                   $!{expSet.put("#${entry.key}", ":${entry.key}")}
                   $!{expNames.put("#${entry.key}", "$entry.key")}
                   $!{expValues.put(":${entry.key}", { "S" : "${entry.value}" })}
               #end
           #end
       #end
   
       ## Start building the update expression, starting with attributes you're going to SET **
       #set( $expression = "" )
       #if( !${expSet.isEmpty()} )
           #set( $expression = "SET" )
           #foreach( $entry in $expSet.entrySet() )
               #set( $expression = "${expression} ${entry.key} = ${entry.value}" )
               #if ( $foreach.hasNext )
                   #set( $expression = "${expression}," )
               #end
           #end
       #end
   
       ## Continue building the update expression, adding attributes you're going to ADD **
       #if( !${expAdd.isEmpty()} )
           #set( $expression = "${expression} ADD" )
           #foreach( $entry in $expAdd.entrySet() )
               #set( $expression = "${expression} ${entry.key} ${entry.value}" )
               #if ( $foreach.hasNext )
                   #set( $expression = "${expression}," )
               #end
           #end
       #end
   
       ## Continue building the update expression, adding attributes you're going to REMOVE **
       #if( !${expRemove.isEmpty()} )
           #set( $expression = "${expression} REMOVE" )
   
           #foreach( $entry in $expRemove )
               #set( $expression = "${expression} ${entry}" )
               #if ( $foreach.hasNext )
                   #set( $expression = "${expression}," )
               #end
           #end
       #end
   
       ## Finally, write the update expression into the document, along with any expressionNames and expressionValues **
       "update" : {
           "expression" : "${expression}"
           #if( !${expNames.isEmpty()} )
               ,"expressionNames" : $utils.toJson($expNames)
           #end
           #if( !${expValues.isEmpty()} )
               ,"expressionValues" : $utils.toJson($expValues)
           #end
       },
   
       "condition" : {
           "expression"       : "version = :expectedVersion",
           "expressionValues" : {
               ":expectedVersion" : $util.dynamodb.toDynamoDBJson($context.arguments.expectedVersion)
           }
       }
   }
   ```

1. 選擇**儲存**。

此範本是更為複雜的範例。它示範映射範本的強大功能和靈活性。它會循環使用所有引數，但會略過 `id` 和 `expectedVersion`。如果引數設為某個項目，則其 ask AWS AppSync 和 DynamoDB 會更新 DynamoDB 中物件上的該屬性。如果屬性設定為 null，則其 asked AWS AppSync 和 DynamoDB 會從後置物件中移除該屬性。若未指定引數，它將會保留該屬性。它會增量 `version` 欄位。

另外，還有新的 `condition` 區段。條件表達式可讓您 tell AWS AppSync 和 DynamoDB，根據在執行操作之前已在 DynamoDB 中的物件狀態，請求是否應成功。在此情況下，只有在 DynamoDB 中目前項目`version`的欄位完全符合`expectedVersion`引數時，您才希望`UpdateItem`請求成功。

如需條件表達式的詳細資訊，請參閱[條件表達式](aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions.md)參考文件。

### 呼叫 API 以更新文章
<a name="id1"></a>

讓我們嘗試使用新解析程式來更新 `Post` 物件：
+ 選擇 **Queries (查詢)** 標籤。
+ 將以下變動貼到 **Queries (查詢)** 窗格。您也必須將 `id` 引數更新為您先前記下的值。

  ```
  mutation updatePost {
    updatePost(
      id:123
      title: "An empty story"
      content: null
      expectedVersion: 2
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ DynamoDB 中更新的文章應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "updatePost": {
        "id": "123",
        "author": "A new author",
        "title": "An empty story",
        "content": null,
        "url": "https://aws.amazon.com/appsync/",
        "ups": 1,
        "downs": 0,
        "version": 3
      }
    }
  }
  ```

在此請求中，您要求 AWS AppSync 和 DynamoDB 僅更新 `title`和 `content` 欄位。它會將所有其他欄位單獨保留 (除了遞增 `version` 欄位)。您將 `title` 屬性設定為新的值，並從文章中移除 `content` 屬性。`author`、`url`、`ups` 和 `downs` 欄位維持原狀。

嘗試再次執行變動要求，讓要求維持原狀。您應該會看到類似以下的回應：

```
{
  "data": {
    "updatePost": null
  },
  "errors": [
    {
      "path": [
        "updatePost"
      ],
      "data": {
        "id": "123",
        "author": "A new author",
        "title": "An empty story",
        "content": null,
        "url": "https://aws.amazon.com/appsync/",
        "ups": 1,
        "downs": 0,
        "version": 3
      },
      "errorType": "DynamoDB:ConditionalCheckFailedException",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "message": "The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ)"
    }
  ]
}
```

條件表達式評估為「false」，因此要求失敗：
+ 第一次執行請求時，DynamoDB 中文章的 `version` 欄位值為 `2`，符合 `expectedVersion`引數。請求成功，這表示 `version` 欄位已在 DynamoDB 中遞增至 `3`。
+ 第二次執行請求時，DynamoDB 中文章的 `version` 欄位值為 `3`，這不符合引`expectedVersion`數。

此模式通常稱為*樂觀鎖定*。

an AWS AppSync DynamoDB 解析程式的一項功能是傳回 DynamoDB 中貼文物件的目前值。您可以在 GraphQL 回應的 `data` 區段 `errors` 欄位中找到此值。您的應用程式可以使用這些資訊來決定繼續執行的方式。在這種情況下，您可以看到 DynamoDB 中物件`version`的欄位設定為 `3`，因此您只要將`expectedVersion`引數更新為 `3`，請求就會再次成功。

如需有關處理條件檢查錯誤的詳細資訊，請參閱[條件表達式](aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions.md)映射範本參考文件。

## 建立 upvotePost 和 downvotePost 變動 (DynamoDB UpdateItem)
<a name="create-upvotepost-and-downvotepost-mutations-ddb-updateitem"></a>

`Post` 類型具有 `ups` 和 `downs` 欄位，可記錄贊同數和不贊同數，但是到目前為止，API 不會讓我們使用它們來執行任何動作。讓我們新增一些變動來對文章表示贊同與不贊同。
+ 選擇 **Schema (結構描述)** 標籤。
+ 修改 **Schema (結構描述)** 窗格中的 `Mutation` 類型以新增 `upvotePost` 和 `downvotePost` 變動，如下所示：

  ```
  type Mutation {
      upvotePost(id: ID!): Post
      downvotePost(id: ID!): Post
      updatePost(
          id: ID!,
          author: String,
          title: String,
          content: String,
          url: String,
          expectedVersion: Int!
      ): Post
      addPost(
          author: String!,
          title: String!,
          content: String!,
          url: String!
      ): Post!
  }
  ```
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**變動**類型上新建立的 **upvotePost** 欄位，然後選擇**連接**。
+ 在**動作功能表中**，選擇**更新執行時間**，然後選擇**單位解析程式 （僅限 VTL)**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "ADD ups :plusOne, version :plusOne",
          "expressionValues" : {
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  $utils.toJson($context.result)
  ```
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**變動**類型上新建立`downvotePost`的欄位，然後選擇**連接**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "ADD downs :plusOne, version :plusOne",
          "expressionValues" : {
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  $utils.toJson($context.result)
  ```
+ 選擇**儲存**。

### 呼叫 API 來對文章表達贊同或不贊同
<a name="call-the-api-to-upvote-and-downvote-a-post"></a>

現在已設定新的解析程式， AWS AppSync 知道如何將傳入`upvotePost`或`downvote`變動轉換為 DynamoDB UpdateItem 操作。您現在可以執行變動，對您之前建立的文章表達贊同或不贊同。
+ 選擇 **Queries (查詢)** 標籤。
+ 將以下變動貼到 **Queries (查詢)** 窗格。您也必須將 `id` 引數更新為您先前記下的值。

  ```
  mutation votePost {
    upvotePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 文章會在 DynamoDB 中更新，並應出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "upvotePost": {
        "id": "123",
        "author": "A new author",
        "title": "An empty story",
        "content": null,
        "url": "https://aws.amazon.com/appsync/",
        "ups": 6,
        "downs": 0,
        "version": 4
      }
    }
  }
  ```
+ 再選擇幾次 **Execute query (執行查詢)**。您應查看在每次執行查詢時以 1 為單位而遞增的 `ups` 和 `version` 欄位。
+ 變更查詢以呼叫 `downvotePost` 變動，如下所示：

  ```
  mutation votePost {
    downvotePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。此時，您應查看在每次執行查詢時以 1 為單位而遞增的 `downs` 和 `version` 欄位。

  ```
  {
    "data": {
      "downvotePost": {
        "id": "123",
        "author": "A new author",
        "title": "An empty story",
        "content": null,
        "url": "https://aws.amazon.com/appsync/",
        "ups": 6,
        "downs": 4,
        "version": 12
      }
    }
  }
  ```

## 設定 deletePost Resolver (DynamoDB DeleteItem)
<a name="setting-up-the-deletepost-resolver-ddb-deletepost"></a>

您要設定的下一個變動是刪除貼文。您將使用 `DeleteItem` DynamoDB 操作來執行此操作。
+ 選擇 **Schema (結構描述)** 標籤。
+ 修改 **Schema (結構描述)** 窗格中的 `Mutation` 類型來新增 `deletePost` 變動，如下所示：

  ```
  type Mutation {
      deletePost(id: ID!, expectedVersion: Int): Post
      upvotePost(id: ID!): Post
      downvotePost(id: ID!): Post
      updatePost(
          id: ID!,
          author: String,
          title: String,
          content: String,
          url: String,
          expectedVersion: Int!
      ): Post
      addPost(
          author: String!,
          title: String!,
          content: String!,
          url: String!
      ): Post!
  }
  ```

  這次您將 `expectedVersion` 欄位設為選用，稍後在您新增要求映射範本時，將對此進行說明。
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**變動**類型上新建立的**刪除**欄位，然後選擇**連接**。
+ 在**動作功能表中**，選擇**更新執行時間**，然後選擇**單位解析程式 （僅限 VTL)**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "DeleteItem",
      "key": {
          "id": $util.dynamodb.toDynamoDBJson($context.arguments.id)
      }
      #if( $context.arguments.containsKey("expectedVersion") )
          ,"condition" : {
              "expression"       : "attribute_not_exists(id) OR version = :expectedVersion",
              "expressionValues" : {
                  ":expectedVersion" : $util.dynamodb.toDynamoDBJson($context.arguments.expectedVersion)
              }
          }
      #end
  }
  ```

   **注意：**`expectedVersion` 引數為可選引數。如果發起人在請求中設定`expectedVersion`引數，則範本會新增一個條件，只有在項目已刪除或 DynamoDB 中的文章`version`屬性完全符合 時，才會允許`DeleteItem`請求成功`expectedVersion`。如果省略，將不會在 `DeleteItem` 要求中指定條件表達式。無論 的值為何`version`，或 DynamoDB 中是否存在該項目，它都會成功。
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  $utils.toJson($context.result)
  ```

   **注意：**即使您正在刪除某個項目，如果該項目尚未刪除，您仍然可以傳回已刪除的項目。
+ 選擇**儲存**。

如需有關 `DeleteItem` 要求映射的詳細資訊，請參閱 [DeleteItem](aws-appsync-resolver-mapping-template-reference-dynamodb-deleteitem.md) 參考文件。

### 呼叫 API 以刪除文章
<a name="call-the-api-to-delete-a-post"></a>

現在已設定解析程式， AWS AppSync 知道如何將傳入`delete`變動轉換為 DynamoDB`DeleteItem` 操作。您現在可以執行變動以在資料表中刪除項目。
+ 選擇 **Queries (查詢)** 標籤。
+ 將以下變動貼到 **Queries (查詢)** 窗格。您也必須將 `id` 引數更新為您先前記下的值。

  ```
  mutation deletePost {
    deletePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 文章會從 DynamoDB 刪除。請注意， AWS AppSync 會傳回從 DynamoDB 刪除的項目值，該值應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "deletePost": {
        "id": "123",
        "author": "A new author",
        "title": "An empty story",
        "content": null,
        "url": "https://aws.amazon.com/appsync/",
        "ups": 6,
        "downs": 4,
        "version": 12
      }
    }
  }
  ```

如果對 `deletePost` 的呼叫實際上是從 DynamoDB 遭到刪除的呼叫，則只會傳回值。
+ 再次選擇 **Execute query (執行查詢)**。
+ 此呼叫仍會成功，但不會傳回任何值。

  ```
  {
    "data": {
      "deletePost": null
    }
  }
  ```

現在讓我們嘗試刪除文章，但這次是指定 `expectedValue`。首先，您需要建立新文章，因為您刪除的正好是您到目前為止所用的文章。
+ 將以下變動貼到 **Queries (查詢)** 窗格：

  ```
  mutation addPost {
    addPost(
      id:123
      author: "AUTHORNAME"
      title: "Our second post!"
      content: "A new post."
      url: "https://aws.amazon.com/appsync/"
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 新建立文章的結果應該會出現在查詢窗格右側的結果窗格中。請記下新建立的物件的 `id`，因為您很快就會用到它。其看起來與下列類似：

  ```
  {
    "data": {
      "addPost": {
        "id": "123",
        "author": "AUTHORNAME",
        "title": "Our second post!",
        "content": "A new post.",
        "url": "https://aws.amazon.com/appsync/",
        "ups": 1,
        "downs": 0,
        "version": 1
      }
    }
  }
  ```

現在讓我們嘗試刪除該文章，但我們將錯誤的值放入 `expectedVersion`：
+ 將以下變動貼到 **Queries (查詢)** 窗格。您也必須將 `id` 引數更新為您先前記下的值。

  ```
  mutation deletePost {
    deletePost(
      id:123
      expectedVersion: 9999
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。

  ```
  {
    "data": {
      "deletePost": null
    },
    "errors": [
      {
        "path": [
          "deletePost"
        ],
        "data": {
          "id": "123",
          "author": "AUTHORNAME",
          "title": "Our second post!",
          "content": "A new post.",
          "url": "https://aws.amazon.com/appsync/",
          "ups": 1,
          "downs": 0,
          "version": 1
        },
        "errorType": "DynamoDB:ConditionalCheckFailedException",
        "locations": [
          {
            "line": 2,
            "column": 3
          }
        ],
        "message": "The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ)"
      }
    ]
  }
  ```

  請求失敗，因為條件表達式評估為 false：DynamoDB 中文章 `version` 的值不符合引數中`expectedValue`指定的 。會在 GraphQL 回應 `data` 區段中 `errors` 欄位傳回物件的目前值。
+ 重試要求，但更正 `expectedVersion`：

  ```
  mutation deletePost {
    deletePost(
      id:123
      expectedVersion: 1
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 這次請求成功，並傳回從 DynamoDB 刪除的值：

  ```
  {
    "data": {
      "deletePost": {
        "id": "123",
        "author": "AUTHORNAME",
        "title": "Our second post!",
        "content": "A new post.",
        "url": "https://aws.amazon.com/appsync/",
        "ups": 1,
        "downs": 0,
        "version": 1
      }
    }
  }
  ```
+ 再次選擇 **Execute query (執行查詢)**。
+ 呼叫仍然成功，但這次不會傳回任何值，因為文章已在 DynamoDB 中刪除。

```
{
  "data": {
    "deletePost": null
  }
}
```

## 設定 allPost 解析程式 (DynamoDB Scan)
<a name="setting-up-the-allpost-resolver-dynamodb-scan"></a>

到目前為止，如果您知道要尋找之每個文章的 `id`，API 才有用。讓我們新增新的解析程式，傳回資料表中的所有文章。
+ 選擇 **Schema (結構描述)** 標籤。
+ 修改 **Schema (結構描述)** 窗格中的 `Query` 類型以新增 `allPost` 查詢，如下所示：

  ```
  type Query {
      allPost(count: Int, nextToken: String): PaginatedPosts!
      getPost(id: ID): Post
  }
  ```
+ 新增 `PaginationPosts` 類型：

  ```
  type PaginatedPosts {
      posts: [Post!]!
      nextToken: String
  }
  ```
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**查詢**類型上新建立的 **allPost** 欄位，然後選擇**連接**。
+ 在**動作功能表中**，選擇**更新執行時間**，然後選擇**單位解析程式 （僅限 VTL)**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "Scan"
      #if( ${context.arguments.count} )
          ,"limit": $util.toJson($context.arguments.count)
      #end
      #if( ${context.arguments.nextToken} )
          ,"nextToken": $util.toJson($context.arguments.nextToken)
      #end
  }
  ```

  此解析程式有兩個選用引數：`count` 會指定單一呼叫中傳回的項目上限數，`nextToken` 可用來擷取下一組結果 (稍後您將顯示 `nextToken` 值來自何處)。
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  {
      "posts": $utils.toJson($context.result.items)
      #if( ${context.result.nextToken} )
          ,"nextToken": $util.toJson($context.result.nextToken)
      #end
  }
  ```

   **注意：**到目前為止，此回應映射範本與所有其他範本皆不同。`allPost` 查詢結果是 `PaginatedPosts`，其中包含文章清單和分頁字符。此物件的形狀與從 the AWS AppSync DynamoDB Resolver 傳回的物件不同：文章清單在 AWS AppSync DynamoDB Resolver 結果`items`中稱為 ，但在 `posts`中稱為 `PaginatedPosts`。
+ 選擇**儲存**。

如需有關 `Scan` 要求映射的詳細資訊，請參閱[掃描](aws-appsync-resolver-mapping-template-reference-dynamodb-scan.md)參考文件。

### 呼叫 API 以掃描所有文章
<a name="call-the-api-to-scan-all-posts"></a>

現在已設定解析程式， AWS AppSync 知道如何將傳入`allPost`查詢轉譯為 DynamoDB`Scan` 操作。您現在可以掃描資料表來擷取所有文章。

在您可以嘗試之前，您必須將一些資料填入資料表，因為您已刪除目前為止所使用的項目。
+ 選擇 **Queries (查詢)** 標籤。
+ 將以下變動貼到 **Queries (查詢)** 窗格：

  ```
  mutation addPost {
    post1: addPost(id:1 author: "AUTHORNAME" title: "A series of posts, Volume 1" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
    post2: addPost(id:2 author: "AUTHORNAME" title: "A series of posts, Volume 2" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
    post3: addPost(id:3 author: "AUTHORNAME" title: "A series of posts, Volume 3" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
    post4: addPost(id:4 author: "AUTHORNAME" title: "A series of posts, Volume 4" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
    post5: addPost(id:5 author: "AUTHORNAME" title: "A series of posts, Volume 5" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
    post6: addPost(id:6 author: "AUTHORNAME" title: "A series of posts, Volume 6" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
    post7: addPost(id:7 author: "AUTHORNAME" title: "A series of posts, Volume 7" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
    post8: addPost(id:8 author: "AUTHORNAME" title: "A series of posts, Volume 8" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
    post9: addPost(id:9 author: "AUTHORNAME" title: "A series of posts, Volume 9" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。

現在，讓我們來掃描資料表，一次會傳回五個結果。
+ 將以下查詢貼到 **Queries (查詢)** 窗格中：

  ```
  query allPost {
    allPost(count: 5) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 前五篇文章應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "allPost": {
        "posts": [
          {
            "id": "5",
            "title": "A series of posts, Volume 5"
          },
          {
            "id": "1",
            "title": "A series of posts, Volume 1"
          },
          {
            "id": "6",
            "title": "A series of posts, Volume 6"
          },
          {
            "id": "9",
            "title": "A series of posts, Volume 9"
          },
          {
            "id": "7",
            "title": "A series of posts, Volume 7"
          }
        ],
        "nextToken": "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnRkJEdXdUK09hcnovRGhNTGxLTGdMUEFBQUI1akNDQWVJR0NTcUdTSWIzRFFFSEJxQ0NBZE13Z2dIUEFnRUFNSUlCeUFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF6ajFodkhKU1paT1pncTRaUUNBUkNBZ2dHWnJiR1dQWGxkMDB1N0xEdGY4Z2JsbktzRjRua1VCcks3TFJLcjZBTFRMeGFwVGJZMDRqOTdKVFQyYVRwSzdzbVdtNlhWWFVCTnFIOThZTzBWZHVkdDI2RlkxMHRqMDJ2QTlyNWJTUWpTbWh6NE5UclhUMG9KZWJSQ2JJbXBlaDRSVlg0Tis0WTVCN1IwNmJQWWQzOVhsbTlUTjBkZkFYMVErVCthaXZoNE5jMk50RitxVmU3SlJ5WmpzMEFkSGduM3FWd2VrOW5oeFVVd3JlK1loUks5QkRzemdiMDlmZmFPVXpzaFZ4cVJRbC93RURlOTcrRmVJdXZNby9NZ1F6dUdNbFRyalpNR3FuYzZBRnhwa0VlZTFtR0FwVDFISElUZlluakptYklmMGUzUmcxbVlnVHVSbDh4S0trNmR0QVoraEhLVDhuNUI3VnF4bHRtSnlNUXBrZGl6KzkyL3VzNDl4OWhrMnVxSW01ZFFwMjRLNnF0dm9ZK1BpdERuQTc5djhzb0grVytYT3VuQ2NVVDY4TVZ1Wk5KYkRuSEFSSEVlaTlVNVBTelU5RGZ6d2pPdmhqWDNJMWhwdWUrWi83MDVHVjlPQUxSTGlwZWZPeTFOZFhwZTdHRDZnQW00bUJUK2c1eC9Ec3ZDbWVnSDFDVXRTdHVuU1ZFa2JpZytQRC9oMUwyRTNqSHhVQldaa28yU256WUc0cG0vV1RSWkFVZHZuQT09In0="
      }
    }
  }
  ```

您取得五個結果以及 `nextToken`，您可以用它來取得下一組結果。
+ 更新 `allPost` 查詢以包括來自之前結果組的 `nextToken`：

  ```
  query allPost {
    allPost(
      count: 5
      nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnRlluNktJRWl6V0ZlR3hJOVJkaStrZUFBQUI1akNDQWVJR0NTcUdTSWIzRFFFSEJxQ0NBZE13Z2dIUEFnRUFNSUlCeUFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5cW8yUGFSZThnalFpemRCTUNBUkNBZ2dHWk1JODhUNzhIOFVUZGtpdFM2ZFluSWRyVDg4c2lkN1RjZzB2d1k3VGJTTWpSQ2U3WjY3TkUvU2I1dWNETUdDMmdmMHErSGJSL0pteGRzYzVEYnE1K3BmWEtBdU5jSENJdWNIUkJ0UHBPWVdWdCtsS2U5L1pNcWdocXhrem1RaXI1YnIvQkt6dU5hZmJCdE93NmtoM2Jna1BKM0RjWWhpMFBGbmhMVGg4TUVGSjBCcXg3RTlHR1V5N0tUS0JLZlV3RjFQZ0JRREdrNzFYQnFMK2R1S2IrVGtZZzVYMjFrc3NyQmFVTmNXZmhTeXE0ZUJHSWhqZWQ5c3VKWjBSSTc2ZnVQdlZkR3FLNENjQmxHYXhpekZnK2pKK1FneEU1SXduRTNYYU5TR0I4QUpmamR2bU1wbUk1SEdvWjlMUUswclczbG14RDRtMlBsaTNLaEVlcm9pem5zcmdINFpvcXIrN2ltRDN3QkJNd3BLbGQzNjV5Nnc4ZnMrK2FnbTFVOUlKOFFrOGd2bEgySHFROHZrZXBrMWlLdWRIQ25LaS9USnBlMk9JeEVPazVnRFlzRTRUU09HUlVJTkxYY2MvdW1WVEpBMUthV2hWTlAvdjNlSnlZQUszbWV6N2h5WHVXZ1BkTVBNWERQdTdjVnVRa3EwK3NhbGZOd2wvSUx4bHNyNDVwTEhuVFpyRWZvVlV1bXZ5S2VKY1RUU1lET05hM1NwWEd2UT09In0="
    ) {
      posts {
        id
        author
      }
      nextToken
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 剩餘的四篇文章應該會出現在查詢窗格右側的結果窗格中。在這組結果中沒有 `nextToken`，因為您已翻遍了所有九篇文章，已經沒有剩餘的文章。其看起來與下列類似：

  ```
  {
    "data": {
      "allPost": {
        "posts": [
          {
            "id": "2",
            "title": "A series of posts, Volume 2"
          },
          {
            "id": "3",
            "title": "A series of posts, Volume 3"
          },
          {
            "id": "4",
            "title": "A series of posts, Volume 4"
          },
          {
            "id": "8",
            "title": "A series of posts, Volume 8"
          }
        ],
        "nextToken": null
      }
    }
  }
  ```

## 設定 allPostsByAuthor 解析程式 (DynamoDB 查詢）
<a name="setting-up-the-allpostsbyauthor-resolver-ddb-query"></a>

除了掃描 DynamoDB 的所有文章之外，您也可以查詢 DynamoDB 以擷取特定作者建立的文章。您先前建立的 DynamoDB 資料表已有`GlobalSecondaryIndex`稱為 的 `author-index` ，您可以使用 DynamoDB`Query` 操作來擷取特定作者建立的所有文章。
+ 選擇 **Schema (結構描述)** 標籤。
+ 修改 **Schema (結構描述)** 窗格中的 `Query` 類型以新增 `allPostsByAuthor` 查詢，如下所示：

  ```
  type Query {
      allPostsByAuthor(author: String!, count: Int, nextToken: String): PaginatedPosts!
      allPost(count: Int, nextToken: String): PaginatedPosts!
      getPost(id: ID): Post
  }
  ```

   **注意：**這會使用與您在 `allPost` 查詢中使用的相同 `PaginatedPosts` 類型。
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**查詢**類型上新建立的 **allPostsByAuthor** 欄位，然後選擇**連接**。
+ 在**動作功能表中**，選擇**更新執行時間**，然後選擇**單位解析程式 （僅限 VTL)**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "Query",
      "index" : "author-index",
      "query" : {
        "expression": "author = :author",
          "expressionValues" : {
            ":author" : $util.dynamodb.toDynamoDBJson($context.arguments.author)
          }
      }
      #if( ${context.arguments.count} )
          ,"limit": $util.toJson($context.arguments.count)
      #end
      #if( ${context.arguments.nextToken} )
          ,"nextToken": "${context.arguments.nextToken}"
      #end
  }
  ```

  如同 `allPost` 解析程式，此解析程式有兩個可選引數：`count`，其會指定項目的上限數，以在單一呼叫中傳回，以及 `nextToken`，其可用來擷取接下來的結果組 (您可從先前的呼叫中取得 `nextToken` 值)。
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  {
      "posts": $utils.toJson($context.result.items)
      #if( ${context.result.nextToken} )
          ,"nextToken": $util.toJson($context.result.nextToken)
      #end
  }
  ```

   **注意**：這是與您在 `allPost` 解析程式中所使用的相同回應映射範本。
+ 選擇**儲存**。

如需有關 `Query` 要求映射的詳細資訊，請參閱[查詢](aws-appsync-resolver-mapping-template-reference-dynamodb-query.md)參考文件。

### 呼叫 API 來查詢某個作者的所有文章
<a name="call-the-api-to-query-all-posts-by-an-author"></a>

現在已設定解析程式， AWS AppSync 知道如何針對`author-index`索引將傳入`allPostsByAuthor`變動轉換為 DynamoDB`Query` 操作。您現在可以查詢資料表以擷取特定作者的所有文章。

在這麼做之前，讓我們再將一些文章填入資料表，因為目前為止每篇文章的作者都一樣。
+ 選擇 **Queries (查詢)** 標籤。
+ 將以下變動貼到 **Queries (查詢)** 窗格：

  ```
  mutation addPost {
    post1: addPost(id:10 author: "Nadia" title: "The cutest dog in the world" content: "So cute. So very, very cute." url: "https://aws.amazon.com/appsync/" ) { author, title }
    post2: addPost(id:11 author: "Nadia" title: "Did you know...?" content: "AppSync works offline?" url: "https://aws.amazon.com/appsync/" ) { author, title }
    post3: addPost(id:12 author: "Steve" title: "I like GraphQL" content: "It's great" url: "https://aws.amazon.com/appsync/" ) { author, title }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。

現在，讓我們查詢資料表，傳回 `Nadia` 撰寫的所有文章。
+ 將以下查詢貼到 **Queries (查詢)** 窗格中：

  ```
  query allPostsByAuthor {
    allPostsByAuthor(author: "Nadia") {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ `Nadia` 撰寫的所有文章應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "allPostsByAuthor": {
        "posts": [
          {
            "id": "10",
            "title": "The cutest dog in the world"
          },
          {
            "id": "11",
            "title": "Did you know...?"
          }
        ],
        "nextToken": null
      }
    }
  }
  ```

分頁適用於 `Query`，如同它適用於 `Scan`。例如，讓我們查詢 `AUTHORNAME` 的所有文章，一次取得五篇。
+ 將以下查詢貼到 **Queries (查詢)** 窗格中：

  ```
  query allPostsByAuthor {
    allPostsByAuthor(
      author: "AUTHORNAME"
      count: 5
    ) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ `AUTHORNAME` 撰寫的所有文章應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "allPostsByAuthor": {
        "posts": [
          {
            "id": "6",
            "title": "A series of posts, Volume 6"
          },
          {
            "id": "4",
            "title": "A series of posts, Volume 4"
          },
          {
            "id": "2",
            "title": "A series of posts, Volume 2"
          },
          {
            "id": "7",
            "title": "A series of posts, Volume 7"
          },
          {
            "id": "1",
            "title": "A series of posts, Volume 1"
          }
        ],
        "nextToken": "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnSExqRnVhVUR3ZUhEZ2QzNGJ2QlFuY0FBQUNqekNDQW9zR0NTcUdTSWIzRFFFSEJxQ0NBbnd3Z2dKNEFnRUFNSUlDY1FZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5Qkg4Yk1obW9LVEFTZHM3SUNBUkNBZ2dKQ3dISzZKNlJuN3pyYUVKY1pWNWxhSkNtZW1KZ0F5N1dhZkc2UEdTNHpNQzJycTkwZHFJTFV6Z25wck9Gd3pMS3VOQ2JvUXc3VDI5eCtnVExIbGg4S3BqbzB1YjZHQ3FwcDhvNDVmMG9JbDlmdS9JdjNXcFNNSXFKTXZ1MEVGVWs1VzJQaW5jZGlUaVRtZFdYWlU1bkV2NkgyRFBRQWZYYlNnSmlHSHFLbmJZTUZZM0FTdmRIL0hQaVZBb1RCMk1YZkg0eGJOVTdEbjZtRFNhb2QwbzdHZHJEWDNtODQ1UXBQUVNyUFhHemY0WDkyajhIdlBCSWE4Smcrb0RxbHozUVQ5N2FXUXdYWWU2S0h4emI1ejRITXdEdXEyRDRkYzhoMi9CbW10MzRMelVGUVIyaExSZGRaZ0xkdzF5cHJZdFZwY3dEc1d4UURBTzdOcjV2ZEp4VVR2TVhmODBRSnp1REhXREpTVlJLdDJwWmlpaXhXeGRwRmNod1BzQ3d2aVBqMGwrcWFFWU1jMXNQbENkVkFGem43VXJrSThWbS8wWHlwR2xZb3BSL2FkV0xVekgrbGMrYno1ZEM2SnVLVXdtY1EyRXlZeDZiS0Izbi9YdUViWGdFeU5PMWZTdE1rRlhyWmpvMVpzdlYyUFRjMzMrdEs0ZDhkNkZrdjh5VVR6WHhJRkxIaVNsOUx6VVdtT3BCaWhrTFBCT09jcXkyOHh1UmkzOEM3UFRqMmN6c3RkOUo1VUY0azBJdUdEbVZzM2xjdWg1SEJjYThIeXM2aEpvOG1HbFpMNWN6R2s5bi8vRE1EbDY3RlJraG5QNFNhSDBpZGI5VFEvMERLeFRBTUdhcWpPaEl5ekVqd2ZDQVJleFdlbldyOGlPVkhScDhGM25WZVdvbFRGK002N0xpdi9XNGJXdDk0VEg3b0laUU5lYmZYKzVOKy9Td25Hb1dyMTlWK0pEb2lIRVFLZ1cwMWVuYjZKUXo5Slh2Tm95ZzF3RnJPVmxGc2xwNlRHa1BlN2Rnd2IrWT0ifQ=="
      }
    }
  }
  ```
+ 使用之前查詢傳回的值更新 `nextToken` 引數，如下所示：

  ```
  query allPostsByAuthor {
    allPostsByAuthor(
      author: "AUTHORNAME"
      count: 5
      nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnSExqRnVhVUR3ZUhEZ2QzNGJ2QlFuY0FBQUNqekNDQW9zR0NTcUdTSWIzRFFFSEJxQ0NBbnd3Z2dKNEFnRUFNSUlDY1FZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5Qkg4Yk1obW9LVEFTZHM3SUNBUkNBZ2dKQ3dISzZKNlJuN3pyYUVKY1pWNWxhSkNtZW1KZ0F5N1dhZkc2UEdTNHpNQzJycTkwZHFJTFV6Z25wck9Gd3pMS3VOQ2JvUXc3VDI5eCtnVExIbGg4S3BqbzB1YjZHQ3FwcDhvNDVmMG9JbDlmdS9JdjNXcFNNSXFKTXZ1MEVGVWs1VzJQaW5jZGlUaVRtZFdYWlU1bkV2NkgyRFBRQWZYYlNnSmlHSHFLbmJZTUZZM0FTdmRIL0hQaVZBb1RCMk1YZkg0eGJOVTdEbjZtRFNhb2QwbzdHZHJEWDNtODQ1UXBQUVNyUFhHemY0WDkyajhIdlBCSWE4Smcrb0RxbHozUVQ5N2FXUXdYWWU2S0h4emI1ejRITXdEdXEyRDRkYzhoMi9CbW10MzRMelVGUVIyaExSZGRaZ0xkdzF5cHJZdFZwY3dEc1d4UURBTzdOcjV2ZEp4VVR2TVhmODBRSnp1REhXREpTVlJLdDJwWmlpaXhXeGRwRmNod1BzQ3d2aVBqMGwrcWFFWU1jMXNQbENkVkFGem43VXJrSThWbS8wWHlwR2xZb3BSL2FkV0xVekgrbGMrYno1ZEM2SnVLVXdtY1EyRXlZeDZiS0Izbi9YdUViWGdFeU5PMWZTdE1rRlhyWmpvMVpzdlYyUFRjMzMrdEs0ZDhkNkZrdjh5VVR6WHhJRkxIaVNsOUx6VVdtT3BCaWhrTFBCT09jcXkyOHh1UmkzOEM3UFRqMmN6c3RkOUo1VUY0azBJdUdEbVZzM2xjdWg1SEJjYThIeXM2aEpvOG1HbFpMNWN6R2s5bi8vRE1EbDY3RlJraG5QNFNhSDBpZGI5VFEvMERLeFRBTUdhcWpPaEl5ekVqd2ZDQVJleFdlbldyOGlPVkhScDhGM25WZVdvbFRGK002N0xpdi9XNGJXdDk0VEg3b0laUU5lYmZYKzVOKy9Td25Hb1dyMTlWK0pEb2lIRVFLZ1cwMWVuYjZKUXo5Slh2Tm95ZzF3RnJPVmxGc2xwNlRHa1BlN2Rnd2IrWT0ifQ=="
    ) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ `AUTHORNAME` 撰寫的其餘文章應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "allPostsByAuthor": {
        "posts": [
          {
            "id": "8",
            "title": "A series of posts, Volume 8"
          },
          {
            "id": "5",
            "title": "A series of posts, Volume 5"
          },
          {
            "id": "3",
            "title": "A series of posts, Volume 3"
          },
          {
            "id": "9",
            "title": "A series of posts, Volume 9"
          }
        ],
        "nextToken": null
      }
    }
  }
  ```

## 使用集
<a name="using-sets"></a>

到目前為止，`Post` 類型為統一金鑰/值物件。您也可以使用 AWS AppSyncDynamoDB 解析程式建立複雜物件的模型，例如集合、清單和映射。

讓我們將 `Post` 類型更新為包含標籤。文章可以有 0 個或多個標籤，這些標籤會以字串集的形式存放在 DynamoDB 中。您也會設定一些變動來新增和移除標籤，以及新查詢以掃描含特定標籤的文章。
+ 選擇 **Schema (結構描述)** 標籤。
+ 修改 **Schema (結構描述)** 窗格中的 `Post` 類型以新增 `tags` 欄位，如下所示：

  ```
  type Post {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int!
    downs: Int!
    version: Int!
    tags: [String!]
  }
  ```
+ 修改 **Schema (結構描述)** 窗格中的 `Query` 類型以新增 `allPostsByTag` 查詢，如下所示：

  ```
  type Query {
    allPostsByTag(tag: String!, count: Int, nextToken: String): PaginatedPosts!
    allPostsByAuthor(author: String!, count: Int, nextToken: String): PaginatedPosts!
    allPost(count: Int, nextToken: String): PaginatedPosts!
    getPost(id: ID): Post
  }
  ```
+ 修改 **Schema (結構描述)** 窗格中的 `Mutation` 類型以新增 `addTag` 和 `removeTag` 變動，如下所示：

  ```
  type Mutation {
    addTag(id: ID!, tag: String!): Post
    removeTag(id: ID!, tag: String!): Post
    deletePost(id: ID!, expectedVersion: Int): Post
    upvotePost(id: ID!): Post
    downvotePost(id: ID!): Post
    updatePost(
      id: ID!,
      author: String,
      title: String,
      content: String,
      url: String,
      expectedVersion: Int!
    ): Post
    addPost(
      author: String!,
      title: String!,
      content: String!,
      url: String!
    ): Post!
  }
  ```
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**查詢**類型上新建立的 **allPostsByTag** 欄位，然後選擇**連接**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "Scan",
      "filter": {
        "expression": "contains (tags, :tag)",
          "expressionValues": {
            ":tag": $util.dynamodb.toDynamoDBJson($context.arguments.tag)
          }
      }
      #if( ${context.arguments.count} )
          ,"limit": $util.toJson($context.arguments.count)
      #end
      #if( ${context.arguments.nextToken} )
          ,"nextToken": $util.toJson($context.arguments.nextToken)
      #end
  }
  ```
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  {
      "posts": $utils.toJson($context.result.items)
      #if( ${context.result.nextToken} )
          ,"nextToken": $util.toJson($context.result.nextToken)
      #end
  }
  ```
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**變動**類型上新建立的 **addTag** 欄位，然後選擇**連接**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "ADD tags :tags, version :plusOne",
          "expressionValues" : {
              ":tags" : { "SS": [ $util.toJson($context.arguments.tag) ] },
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  $utils.toJson($context.result)
  ```
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**變動**類型上新建立的 **removeTag** 欄位，然後選擇**連接**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "DELETE tags :tags ADD version :plusOne",
          "expressionValues" : {
              ":tags" : { "SS": [ $util.toJson($context.arguments.tag) ] },
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  $utils.toJson($context.result)
  ```
+ 選擇**儲存**。

### 呼叫 API 來使用標籤
<a name="call-the-api-to-work-with-tags"></a>

現在您已設定解析程式， AWS AppSync 知道如何將傳入的 `removeTag`、 `addTag`和 `allPostsByTag`請求轉換為 DynamoDB`UpdateItem` 和 `Scan`操作。

為了嘗試看看，讓我們選擇您先前建立的其中一篇文章。例如，讓我們使用 `Nadia` 撰寫的一篇文章。
+ 選擇 **Queries (查詢)** 標籤。
+ 將以下查詢貼到 **Queries (查詢)** 窗格中：

  ```
  query allPostsByAuthor {
    allPostsByAuthor(
      author: "Nadia"
    ) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ Nadia 的所有文章應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "allPostsByAuthor": {
        "posts": [
          {
            "id": "10",
            "title": "The cutest dog in the world"
          },
          {
            "id": "11",
            "title": "Did you known...?"
          }
        ],
        "nextToken": null
      }
    }
  }
  ```
+ 我們使用標題為 `"The cutest dog in the world"` 的文章。請記下其 `id`，因為您稍後將會用到它。

現在，讓我們嘗試新增 `dog` 標籤。
+ 將以下變動貼到 **Queries (查詢)** 窗格。您也必須將 `id` 引數更新為您先前記下的值。

  ```
  mutation addTag {
    addTag(id:10 tag: "dog") {
      id
      title
      tags
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 使用新標籤更新的文章。

  ```
  {
    "data": {
      "addTag": {
        "id": "10",
        "title": "The cutest dog in the world",
        "tags": [
          "dog"
        ]
      }
    }
  }
  ```

您可以新增更多的標籤，如下所示：
+ 更新變動以將 `tag` 引數變更為 `puppy`。

  ```
  mutation addTag {
    addTag(id:10 tag: "puppy") {
      id
      title
      tags
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 使用新標籤更新的文章。

  ```
  {
    "data": {
      "addTag": {
        "id": "10",
        "title": "The cutest dog in the world",
        "tags": [
          "dog",
          "puppy"
        ]
      }
    }
  }
  ```

您也可以刪除標籤：
+ 將以下變動貼到 **Queries (查詢)** 窗格。您也必須將 `id` 引數更新為您先前記下的值。

  ```
  mutation removeTag {
    removeTag(id:10 tag: "puppy") {
      id
      title
      tags
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 貼文將會更新，且 `puppy` 標籤將會刪除。

  ```
  {
    "data": {
      "addTag": {
        "id": "10",
        "title": "The cutest dog in the world",
        "tags": [
          "dog"
        ]
      }
    }
  }
  ```

您也可以搜尋所有包含標籤的貼文：
+ 將以下查詢貼到 **Queries (查詢)** 窗格中：

  ```
  query allPostsByTag {
    allPostsByTag(tag: "dog") {
      posts {
        id
        title
        tags
      }
      nextToken
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ 具有 `dog` 標籤的所有文章將會傳回，如下所示：

  ```
  {
    "data": {
      "allPostsByTag": {
        "posts": [
          {
            "id": "10",
            "title": "The cutest dog in the world",
            "tags": [
              "dog",
              "puppy"
            ]
          }
        ],
        "nextToken": null
      }
    }
  }
  ```

## 使用清單和映射
<a name="using-lists-and-maps"></a>

除了使用 DynamoDB 集之外，您還可以使用 DynamoDB 清單和映射在單一物件中建立複雜資料的模型。

讓我們新增功能以將評論新增到文章。這將建模為 DynamoDB 中物件上的映射`Post`物件清單。

 **注意：**在實際應用程式中，您會在它們自己的資料表中塑造評論。在本教學課程中，您將只是將它們新增至 `Post` 資料表。
+ 選擇 **Schema (結構描述)** 標籤。
+ 修改 **Schema (結構描述)** 窗格中新增 `Comment` 類型，如下所示：

  ```
  type Comment {
      author: String!
      comment: String!
  }
  ```
+ 修改 **Schema (結構描述)** 窗格中的 `Post` 類型以新增 `comments` 欄位，如下所示：

  ```
  type Post {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int!
    downs: Int!
    version: Int!
    tags: [String!]
    comments: [Comment!]
  }
  ```
+ 修改 **Schema (結構描述)** 窗格中的 `Mutation` 類型來新增 `addComment` 變動，如下所示：

  ```
  type Mutation {
    addComment(id: ID!, author: String!, comment: String!): Post
    addTag(id: ID!, tag: String!): Post
    removeTag(id: ID!, tag: String!): Post
    deletePost(id: ID!, expectedVersion: Int): Post
    upvotePost(id: ID!): Post
    downvotePost(id: ID!): Post
    updatePost(
      id: ID!,
      author: String,
      title: String,
      content: String,
      url: String,
      expectedVersion: Int!
    ): Post
    addPost(
      author: String!,
      title: String!,
      content: String!,
      url: String!
    ): Post!
  }
  ```
+ 選擇**儲存**。
+ 在右側的**資料類型**窗格中，尋找**變動**類型上新建立的 **addComment** 欄位，然後選擇**連接**。
+ 在 **Data source name (資料來源名稱)** 中，選擇 **PostDynamoDBTable**。
+ 將以下內容貼到 **Configure the request mapping template (設定請求映射範本)** 區段：

  ```
  {
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : {
      "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
    },
    "update" : {
      "expression" : "SET comments = list_append(if_not_exists(comments, :emptyList), :newComment) ADD version :plusOne",
      "expressionValues" : {
        ":emptyList": { "L" : [] },
        ":newComment" : { "L" : [
          { "M": {
            "author": $util.dynamodb.toDynamoDBJson($context.arguments.author),
            "comment": $util.dynamodb.toDynamoDBJson($context.arguments.comment)
            }
          }
        ] },
        ":plusOne" : $util.dynamodb.toDynamoDBJson(1)
      }
    }
  }
  ```

  這個更新表達式將會將包含新評論的清單附加到現有的 `comments` 清單。如果清單不存在，則會建立一個。
+ 將以下內容貼到 **Configure the response mapping template (設定回應映射範本)** 區段：

  ```
  $utils.toJson($context.result)
  ```
+ 選擇**儲存**。

### 呼叫 API 以新增評論
<a name="call-the-api-to-add-a-comment"></a>

現在您已設定解析程式， AWS AppSync 知道如何將傳入`addComment`的請求轉換為 DynamoDB`UpdateItem` 操作。

讓我們透過將評論新增至您已新增標籤的相同文章，以嘗試此操作。
+ 選擇 **Queries (查詢)** 標籤。
+ 將以下查詢貼到 **Queries (查詢)** 窗格中：

  ```
  mutation addComment {
    addComment(
      id:10
      author: "Steve"
      comment: "Such a cute dog."
    ) {
      id
      comments {
        author
        comment
      }
    }
  }
  ```
+ 選擇 **Execute query (執行查詢)** (橘色播放按鈕)。
+ Nadia 的所有文章應該會出現在查詢窗格右側的結果窗格中。其看起來與下列類似：

  ```
  {
    "data": {
      "addComment": {
        "id": "10",
        "comments": [
          {
            "author": "Steve",
            "comment": "Such a cute dog."
          }
        ]
      }
    }
  }
  ```

如果您多次執行要求，系統會將多個評論附加到清單。

## 結論
<a name="conclusion"></a>

在本教學課程中，您已建置 API，讓我們可以使用 AWS AppSync 和 GraphQL 在 DynamoDB 中操作 Post 物件。如需詳細資訊，請參閱[解析程式映射範本參考](resolver-mapping-template-reference.md#aws-appsync-resolver-mapping-template-reference)。

若要清除，您可以從主控台將 AppSync GraphQL API 刪除。

若要刪除您為此教學課程建立的 DynamoDB 資料表和 IAM 角色，您可以執行下列動作來刪除`AWSAppSyncTutorialForAmazonDynamoDB`堆疊，或造訪 CloudFormation 主控台並刪除堆疊：

```
aws cloudformation delete-stack \
    --stack-name AWSAppSyncTutorialForAmazonDynamoDB
```