

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# 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 に接続する方法を示します。

ユーザーに代わって DynamoDB リソースをプロビジョニングすることを AWS AppSync に許可できます。または、必要であれば、データソースとリゾルバーを作成することで、既存のテーブルを 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
   ```

   または、アカウントの米国西部 2 (オレゴン) リージョンで次の CloudFormation スタックを起動することもできます AWS 。

   [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)

   これにより、以下の項目が作成されます。
   + データを保持するDynamoDBテーブルが`AppSyncTutorial-Post`呼び出されます。`Post`
   +  AWS AppSync が`Post`テーブルとやり取りできるようにする IAM ロールおよび関連する IAM 管理ポリシー。

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. **API ダッシュボード**で、**[API の作成]** を選択します。

1. **[API をカスタマイズまたは Amazon DynamoDB からインポート]** ウィンドウで、**[一から構築]** を選択します。

   1. 同じウィンドウの右にある **[開始]** を選択します。

1. **[API 名]** フィールドで、API の名前を `AWSAppSyncTutorial` に設定します。

1. **[作成]** を選択します。

 AWS AppSync コンソールは、API キー認証モードを使用して新しい GraphQL API を作成します。このコンソールを使用して、残りの GraphQL API をセットアップでき、このチュートリアルの残りの部分でクエリを実行できます。

## 基本的な Post API の定義
<a name="defining-a-basic-post-api"></a>

 AWS AppSync GraphQL API を作成したので、ポストデータの基本作成、取得、削除を許可する基本スキーマを設定できます。

1. にサインイン AWS マネジメントコンソール し、[AppSync コンソール](https://console.aws.amazon.com/appsync/)を開きます。

   1. **API ダッシュボード**で、先ほど作成した 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. **API ダッシュボード**で、GraphQL API を選択します。

   1. **サイドバー** で **[データソース]** を選択します。

1. **[データソースを作成]** を選択します。

   1. **データソース名**には、`PostDynamoDBTable` を入力します。

   1. **[データソースタイプ]** として **[Amazon DynamoDB テーブル]** を選択します。

   1. **[リージョン]** として **[US-WEST-2]** を選択します。

   1. **[テーブル名]** には、**[AppSyncTutorial-Post]** DynamoDB テーブルを選択します。

   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-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>

 AWS AppSync が DynamoDB テーブルを認識したら、**リゾルバー**を定義して個々のクエリとミューテーションにリンクできます。最初に作成するリゾルバーは `addPost` リゾルバーです。このリゾルバーによって、ユーザーが `AppSyncTutorial-Post` DynamoDB テーブルにポストを作成できるようになります。

リゾルバーには以下のコンポーネントがあります。
+ リゾルバーをアタッチする、GraphQL スキーマ内の場所。この例では、`addPost` 型の `Mutation` フィールドにリゾルバーをセットアップしています。このリゾルバーは、呼び出し元が `mutation { addPost(...){...} }` を呼び出したときに呼び出されます。
+ このリゾルバーで使用するデータソース。この例では、`PostDynamoDBTable` DynamoDB テーブルにエントリを追加できるように、前に定義した `AppSyncTutorial-Post` データソースを使用します。
+ リクエストマッピングテンプレート。リクエストマッピングテンプレートの目的は、発信者からの受信リクエストを受け取り、それを AWS AppSync が DynamoDB に対して実行する手順に変換することです。
+ レスポンスマッピングテンプレート。レスポンスマッピングテンプレートの目的は、DynamoDB からのレスポンスを取り込み、それを GraphQL で想定されているものに変換し直すことです。これは、DynamoDB でのデータのシェイプが GraphQL での `Post` 型と異なる場合に便利です。ただし、この例では、両方のシェイプが同じであるため、データをそのまま渡します。

リゾルバーをセットアップするには、以下の手順に従います。

1. にサインイン AWS マネジメントコンソール し、[AppSync コンソール](https://console.aws.amazon.com/appsync/)を開きます。

   1. **API ダッシュボード**で、GraphQL API を選択します。

   1. **サイドバー** で **[データソース]** を選択します。

1. **[データソースを作成]** を選択します。

   1. **データソース名**には、`PostDynamoDBTable` を入力します。

   1. **[データソースタイプ]** として **[Amazon DynamoDB テーブル]** を選択します。

   1. **[リージョン]** として **[US-WEST-2]** を選択します。

   1. **[テーブル名]** には、**[AppSyncTutorial-Post]** DynamoDB テーブルを選択します。

   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. **[作成]** を選択します。

1. [**Schema (スキーマ)**] タブを選択します。

1. 右側の**データ型**ペインで、**ミューテーション**型の**addPost**フィールドを見つけて、**アタッチ**を選択します。

1. **[アクション]** メニューで **[ランタイムの更新]** を選択し、**[ユニットリゾルバー (VTL のみ)]** を選択します。

1. **[データソース名]** で、**[PostDynamoDBTable]** を選択します。

1. 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

   ```
   {
       "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` フィールドの初期化も行っています。

   このチュートリアルでは、DynamoDB に挿入される新しい項目のインデックスを作成する GraphQL `ID!`タイプが、クライアント arguments. AWS AppSync comes の一部として、 という名前の自動 ID 生成用のユーティリティとともに提供されることを指定しました。`$utils.autoId()`これは、 の形式でも使用できます`"id" : { "S" : "${$utils.autoId()}" }`。そのため、`id: ID!` を `addPost()` のスキーマ定義から除外するだけで、自動的に挿入されます。このチュートリアルではこの手法を使用しませんが、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. 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

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

    **注 :** `AppSyncTutorial-Post` テーブルでのデータのシェイプは GraphQL での `Post` 型のシェイプと厳密に一致しているため、このレスポンスマッピングテンプレートは結果をそのまま渡すだけです。また、このチュートリアルのすべての例では、これと同じレスポンスマッピングテンプレートだけを使用しているため、作成するファイルはこの 1 つだけです。

1. **[保存]** を選択します。

### ポストを追加する API の呼び出し
<a name="call-the-api-to-add-a-post"></a>

これでリゾルバーがセットアップされたので、 AWS AppSync は着信`addPost`ミューテーションを DynamoDB PutItem オペレーションに変換できます。ユーザーはミューテーションを実行してテーブルに何かを入れることができるようになりました。
+ **[クエリ]** タブを選択します。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。

  ```
  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 テーブルにデータを追加できるようになりました。次は、`AppSyncTutorial-Post` テーブルからデータを取得できるように、`getPost` クエリを設定する必要があります。そのためには、別のリゾルバーを設定します。
+ [**Schema (スキーマ)**] タブを選択します。
+ 右側の**データ型**ペインで、**Query**型の**getPost**フィールドを見つけて、[**アタッチ**] を選択します。
+ **[アクション]** メニューで **[ランタイムの更新]** を選択し、**[ユニットリゾルバー (VTL のみ)]** を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "version" : "2017-02-28",
      "operation" : "GetItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
      }
  }
  ```
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

  ```
  $utils.toJson($context.result)
  ```
+ **[保存]** を選択します。

### ポストを取得する API の呼び出し
<a name="call-the-api-to-get-a-post"></a>

これでリゾルバーが設定され、 AWS AppSync は受信`getPost`クエリを DynamoDB`GetItem` オペレーションに変換する方法を知っています。次は、先ほど作成したポストを取得するクエリを実行します。
+ **[クエリ]** タブを選択します。
+ [**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 から AWS AppSyncへの不要なデータ転送を避けるため、投影式を使用して DynamoDB テーブルから必要な属性のみを指定するようにリクエストマッピングテンプレートを変更できます。例えば、リクエストマッピングテンプレートは以下のスニペットのようになります。

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

## updatePost ミューテーション (DynamoDB UpdateItem) の作成
<a name="create-an-updatepost-mutation-ddb-updateitem"></a>

これで、DynamoDB 内の `Post` オブジェクトを作成および取得できるようになりました。次は、オブジェクトを更新できるように、新しいミューテーションを設定します。そのためには、DynamoDB の UpdateItem オペレーションを使用します。
+ [**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 のみ)]** を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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 の更新式を使用します。その式自体は、`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)」のドキュメントを参照してください。
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

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

### ポストを更新する API の呼び出し
<a name="call-the-api-to-update-a-post"></a>

これでリゾルバーが設定され、 AWS AppSync は着信`update`ミューテーションを DynamoDB`Update` オペレーションに変換する方法を知っています。ユーザーは、前のステップで書き込んだ項目を更新するミューテーションを実行できるようになりました。
+ **[クエリ]** タブを選択します。
+ 次のミューテーションを [**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
      }
    }
  }
  ```

この例では、リクエストマッピングテンプレートが AWS AppSync `ups`と DynamoDB にそれらの`downs`フィールドで何もするように要求しなかったため、 フィールドと フィールドは変更されませんでした。また、`version` フィールドが 1 ずつ増加します。これは、`version` フィールドに 1 を追加するように AWS AppSync と DynamoDB に指示しているためです。

## updatePost リゾルバー (DynamoDB UpdateItem) の変更
<a name="modifying-the-updatepost-resolver-dynamodb-updateitem"></a>

`updatePost` ミューテーションの手始めとしてはこれで十分ですが、次の 2 つの主な問題があります。
+ 1 つのフィールドだけを更新する場合でも、すべてのフィールドを更新する必要があります。
+ 2 人のユーザーがこのオブジェクトを変更すると、情報が失われる可能性があります。

これらの問題に対処するために、リクエストで指定された引数のみを変更し、`UpdateItem` オペレーションに条件を追加するように、`updatePost` ミューテーションを修正します。

1. [**Schema (スキーマ)**] タブを選択します。

1. **[スキーマ]** ペインで `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. 右側の [**Data types (データ型)**] ペインで、**ミューテーション**型の **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` をスキップしています。引数が何かに設定されている場合、DynamoDB のオブジェクトでその属性を更新するように AWS AppSync と DynamoDB に要求します。属性が null に設定されている場合、 AWS AppSync と DynamoDB にポストオブジェクトからその属性を削除するように要求します。引数が指定されていない場合、その属性は元のままになります。また、`version` フィールドが増分されます。

また、新しい `condition` セクションがあります。条件式を使用すると、オペレーションが実行される前に既に DynamoDB にあるオブジェクトの状態に基づいて、リクエストが成功するかどうかを AWS AppSync と DynamoDB に指示できます。この例では、DynamoDB に現在ある項目の `version` フィールドが `expectedVersion` 引数と厳密に一致する場合にのみ、`UpdateItem` リクエストが成功するように指示しています。

条件式の詳細については、「[条件式](aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions.md)」リファレンスドキュメントを参照してください。

### ポストを更新する API の呼び出し
<a name="id1"></a>

新しいリゾルバーで `Post` オブジェクトを更新してみましょう。
+ **[クエリ]** タブを選択します。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。また、`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` 引数と一致していました。このリクエストは成功し、DynamoDB で `version` フィールドが `3` に増分されました。
+ このリクエストを 2 回目に実行したときに、DynamoDB 内のこのポストの `version` フィールドの値は `3` であり、`expectedVersion` 引数と一致していませんでした。

このパターンは通常、「*楽観的ロック*」と呼ばれます。

 AWS AppSync DynamoDB リゾルバーの機能の 1 つは、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 (スキーマ)**] タブを選択します。
+ **[スキーマ]** ペインの `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 のみ)]** を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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 }
          }
      }
  }
  ```
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

  ```
  $utils.toJson($context.result)
  ```
+ **[保存]** を選択します。
+ 右側の**データ型**ペインで、**ミューテーション**型の新しく作成された `downvotePost` フィールドを見つけて、[**アタッチ**] を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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 }
          }
      }
  }
  ```
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

  ```
  $utils.toJson($context.result)
  ```
+ **[保存]** を選択します。

### ポストに賛成および反対するための API の呼び出し
<a name="call-the-api-to-upvote-and-downvote-a-post"></a>

これで新しいリゾルバーが設定され、 AWS AppSync は受信`upvotePost`または`downvote`ミューテーションを DynamoDB UpdateItem オペレーションに変換する方法を知っています。これで、先ほど作成したポストに賛成または反対するミューテーションを実行できるようになりました。
+ **[クエリ]** タブを選択します。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。また、`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 (クエリを実行)**] を選択します。このクエリを実行するたびに、`ups` フィールドと `version` フィールドが 1 つずつ増加することを確認できます。
+ 次のようにクエリを変更し、`downvotePost` ミューテーションを呼び出します。

  ```
  mutation votePost {
    downvotePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ [**Execute query (クエリを実行)**] (オレンジ色の再生ボタン) を選択します。今度は、このクエリを実行するたびに、`downs` フィールドと `version` フィールドが 1 つずつ増加することを確認できます。

  ```
  {
    "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 リゾルバー (DynamoDB DeletePost) のセットアップ
<a name="setting-up-the-deletepost-resolver-ddb-deletepost"></a>

次は、ポストを削除するミューテーションを設定します。そのためには、DynamoDB の `DeleteItem` オペレーションを使用します。
+ [**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` フィールドを省略可能にしています。これについては、リクエストマッピングテンプレートを追加するときに説明します。
+ **[保存]** を選択します。
+ 右側の**データ型**ペインで、**ミューテーション**型の新しく作成された **delete** フィールドを見つけて、[**アタッチ**] を選択します。
+ **[アクション]** メニューで **[ランタイムの更新]** を選択し、**[ユニットリゾルバー (VTL のみ)]** を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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` 属性が `expectedVersion` と完全に一致する場合にのみ、`DeleteItem` リクエストが成功することを許可する条件が、テンプレートによって追加されます。この引数が省略されている場合は、`DeleteItem` リクエストで条件式が指定されていません。`version` の値や項目が DynamoDB に存在するかどうかに関係なく、成功します。
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

  ```
  $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` オペレーションに変換する方法を知っています。ユーザーはミューテーションを実行してテーブル内の何かを削除できるようになりました。
+ **[クエリ]** タブを選択します。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。また、`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 から項目が削除された場合にのみ返されます。
+ **[クエリを実行]** を再度選択します。
+ この呼び出しは成功しますが、値は返されません。

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

次は、`expectedValue` を指定して、ポストを削除してみましょう。ただし、これまで使用してきたポストは削除したため、まず新しいポストを作成する必要があります。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。

  ```
  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` に間違った値を入れて、ポストを削除してみましょう。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。また、`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
      }
    }
  }
  ```
+ **[クエリを実行]** を再度選択します。
+ この呼び出しは成功しますが、そのポストが DynamoDB で既に削除されているため、今回は値が返されません。

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

## allPost リゾルバー (DynamoDB Scan) のセットアップ
<a name="setting-up-the-allpost-resolver-dynamodb-scan"></a>

これまでのところ、APIは、見たい各投稿の `id` がわかっている場合にのみ便利です。テーブル内のすべてのポストを返す新しいリゾルバーを追加してみましょう。
+ [**Schema (スキーマ)**] タブを選択します。
+ **[スキーマ]** ペインの `Query` タイプを次のように変更して、新しい `allPost` クエリを追加します。

  ```
  type Query {
      allPost(count: Int, nextToken: String): PaginatedPosts!
      getPost(id: ID): Post
  }
  ```
+ 新しい `PaginationPosts` 型を追加します。

  ```
  type PaginatedPosts {
      posts: [Post!]!
      nextToken: String
  }
  ```
+ **[保存]** を選択します。
+ 右側の**データ型**ペインで、**ミューテーション**型の新しく作成された **allPost** フィールドを見つけて、[**アタッチ**] を選択します。
+ **[アクション]** メニューで **[ランタイムの更新]** を選択し、**[ユニットリゾルバー (VTL のみ)]** を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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
  }
  ```

  このリゾルバーには、省略可能な 2 つの引数があります。`count` では、1 回の呼び出しで返される項目の最大数を指定し、`nextToken` は、次の結果セットを取得するために使用できます (`nextToken` の値がどのように生成されるかについては、後で説明します)。
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

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

   **注 :** このレスポンスマッピングテンプレートは、これまで他の例で使用したものとは異なります。`allPost` クエリの結果は `PaginatedPosts` であり、ポストのリストとページ分割トークンが含まれています。このオブジェクトの形状は、 AWS AppSync DynamoDB Resolver から返されるものと異なります。投稿のリストは AWS AppSync DynamoDB Resolver の結果`items`で呼び出されますが、 `posts`では呼び出されます`PaginatedPosts`。
+ **[保存]** を選択します。

`Scan` リクエストマッピングの詳細については、「[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` オペレーションに変換する方法を知っています。ユーザーは、テーブルをスキャンしてすべてのポストを取得できるようになりました。

ただし、これまで使用してきたデータはすべて削除したため、これを試す前にテーブルにデータを入力しておく必要があります。
+ **[クエリ]** タブを選択します。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。

  ```
  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 (クエリを実行)**] (オレンジ色の再生ボタン) を選択します。

では、テーブルをスキャンして、一度に 5 個の結果を返しましょう。
+ 以下のクエリを **[クエリ]** ペインに貼り付けます。

  ```
  query allPost {
    allPost(count: 5) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ [**Execute query (クエリを実行)**] (オレンジ色の再生ボタン) を選択します。
+ 最初の 5 個のポストが、クエリペインの右側にある結果ペインに表示されます。これは次のように表示されます。

  ```
  {
    "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="
      }
    }
  }
  ```

5 つの結果と `nextToken` を取得しました。このトークンを使用して、次の結果セットを取得できます。
+ 前回の結果セットからの `allPost` を含めるように、`nextToken` クエリを更新します。

  ```
  query allPost {
    allPost(
      count: 5
      nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnRlluNktJRWl6V0ZlR3hJOVJkaStrZUFBQUI1akNDQWVJR0NTcUdTSWIzRFFFSEJxQ0NBZE13Z2dIUEFnRUFNSUlCeUFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5cW8yUGFSZThnalFpemRCTUNBUkNBZ2dHWk1JODhUNzhIOFVUZGtpdFM2ZFluSWRyVDg4c2lkN1RjZzB2d1k3VGJTTWpSQ2U3WjY3TkUvU2I1dWNETUdDMmdmMHErSGJSL0pteGRzYzVEYnE1K3BmWEtBdU5jSENJdWNIUkJ0UHBPWVdWdCtsS2U5L1pNcWdocXhrem1RaXI1YnIvQkt6dU5hZmJCdE93NmtoM2Jna1BKM0RjWWhpMFBGbmhMVGg4TUVGSjBCcXg3RTlHR1V5N0tUS0JLZlV3RjFQZ0JRREdrNzFYQnFMK2R1S2IrVGtZZzVYMjFrc3NyQmFVTmNXZmhTeXE0ZUJHSWhqZWQ5c3VKWjBSSTc2ZnVQdlZkR3FLNENjQmxHYXhpekZnK2pKK1FneEU1SXduRTNYYU5TR0I4QUpmamR2bU1wbUk1SEdvWjlMUUswclczbG14RDRtMlBsaTNLaEVlcm9pem5zcmdINFpvcXIrN2ltRDN3QkJNd3BLbGQzNjV5Nnc4ZnMrK2FnbTFVOUlKOFFrOGd2bEgySHFROHZrZXBrMWlLdWRIQ25LaS9USnBlMk9JeEVPazVnRFlzRTRUU09HUlVJTkxYY2MvdW1WVEpBMUthV2hWTlAvdjNlSnlZQUszbWV6N2h5WHVXZ1BkTVBNWERQdTdjVnVRa3EwK3NhbGZOd2wvSUx4bHNyNDVwTEhuVFpyRWZvVlV1bXZ5S2VKY1RUU1lET05hM1NwWEd2UT09In0="
    ) {
      posts {
        id
        author
      }
      nextToken
    }
  }
  ```
+ [**Execute query (クエリを実行)**] (オレンジ色の再生ボタン) を選択します。
+ 残りの 4 個のポストが、クエリペインの右側にある結果ペインに表示されます。9 個のポストのすべてをページ分割して、ポストは残っていないため、この結果セットに `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 テーブルには、既に `author-index` という `GlobalSecondaryIndex` があるため、DynamoDB の `Query` オペレーションでそれを使用して、特定の作成者が作成したすべてのポストを取得できます
+ [**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 のみ)]** を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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` リゾルバーと同様に、このリゾルバーには、省略可能な 2 つの引数があります。`count` では、1 回の呼び出しで返される項目の最大数を指定し、`nextToken` は、次の結果セットを取得するために使用できます (`nextToken` の値は前回の呼び出しから取得できます)。
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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 は受信`allPostsByAuthor`ミューテーションを`author-index`インデックスに対する DynamoDB`Query` オペレーションに変換する方法を知っています。ユーザーは、テーブルをクエリして、特定の作成者によるポストをすべて取得できます。

ただし、これまで使用していたポストはすべて同じ作成者だったため、それを行う前に、テーブルにポストを追加しておきましょう。
+ **[クエリ]** タブを選択します。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。

  ```
  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` が作成したすべてのポストを返すクエリを実行しましょう。
+ 以下のクエリを **[クエリ]** ペインに貼り付けます。

  ```
  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` によるすべてのポストを検索して、一度に 5 個ずつ取得します。
+ 以下のクエリを **[クエリ]** ペインに貼り付けます。

  ```
  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` 型を更新して、タグを含めましょう。1 つのポストには、DynamoDB に文字列として保存されているタグを 0 個以上付けることができます。タグを追加および削除するミューテーションと、特定のタグが付いているポストをスキャンする新しいクエリもセットアップします。
+ [**Schema (スキーマ)**] タブを選択します。
+ **[スキーマ]** ペインの `Post` タイプを次のように変更して、新しい `tags` フィールドを追加します。

  ```
  type Post {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int!
    downs: Int!
    version: Int!
    tags: [String!]
  }
  ```
+ **[スキーマ]** ペインの `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
  }
  ```
+ **[スキーマ]** ペインの `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** フィールドを見つけて、[**アタッチ**] を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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
  }
  ```
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "posts": $utils.toJson($context.result.items)
      #if( ${context.result.nextToken} )
          ,"nextToken": $util.toJson($context.result.nextToken)
      #end
  }
  ```
+ **[保存]** を選択します。
+ 右側の**データ型**ペインで、**ミューテーション**型の新しく作成された **addTag** フィールドを見つけて、[**アタッチ**] を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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 }
          }
      }
  }
  ```
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

  ```
  $utils.toJson($context.result)
  ```
+ **[保存]** を選択します。
+ 右側の**データ型**ペインで、**ミューテーション**型の新しく作成された **removeTag** フィールドを見つけて、[**アタッチ**] を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
      "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 }
          }
      }
  }
  ```
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

  ```
  $utils.toJson($context.result)
  ```
+ **[保存]** を選択します。

### タグを操作する API の呼び出し
<a name="call-the-api-to-work-with-tags"></a>

リゾルバーをセットアップしたので、 AWS AppSync は受信 `addTag`、、`removeTag`および `allPostsByTag`リクエストを DynamoDB`UpdateItem` および `Scan`オペレーションに変換する方法を理解しています。

それを試すには、前のステップで作成したポストのいずれかを選択します。例えば、`Nadia` が作成したポストを使用しましょう。
+ **[クエリ]** タブを選択します。
+ 以下のクエリを **[クエリ]** ペインに貼り付けます。

  ```
  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` タグを追加してみましょう。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。また、`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"
        ]
      }
    }
  }
  ```

次のようにタグを追加できます。
+ `puppy` に変更するように、`tag` 引数を更新します。

  ```
  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"
        ]
      }
    }
  }
  ```

タグを削除することもできます。
+ 以下のミューテーションを **[クエリ]** ペインに貼り付けます。また、`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"
        ]
      }
    }
  }
  ```

タグが付いているすべてのポストを検索することもできます。
+ 以下のクエリを **[クエリ]** ペインに貼り付けます。

  ```
  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!
  }
  ```
+ **[スキーマ]** ペインの `Post` タイプを次のように変更して、新しい `comments` フィールドを追加します。

  ```
  type Post {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int!
    downs: Int!
    version: Int!
    tags: [String!]
    comments: [Comment!]
  }
  ```
+ **[スキーマ]** ペインの `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** フィールドを見つけて、[**アタッチ**] を選択します。
+ **[データソース名]** で、**[PostDynamoDBTable]** を選択します。
+ 以下のコードを **[リクエストマッピングテンプレートの設定]** に貼り付けます。

  ```
  {
    "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` リストに追加されます。リストがまだ存在しない場合は作成されます。
+ 以下のコードを **[レスポンスマッピングテンプレートの設定]** に貼り付けます。

  ```
  $utils.toJson($context.result)
  ```
+ **[保存]** を選択します。

### コメントを追加する API の呼び出し
<a name="call-the-api-to-add-a-comment"></a>

リゾルバーをセットアップしたので、 AWS AppSync は受信`addComment`リクエストを DynamoDB`UpdateItem` オペレーションに変換する方法を理解しています。

タグを追加したのと同じポストにコメントを追加して、試してみましょう。
+ **[クエリ]** タブを選択します。
+ 以下のクエリを **[クエリ]** ペインに貼り付けます。

  ```
  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>

このチュートリアルでは、 AWS AppSync と GraphQL を使用して DynamoDB 内のポストオブジェクトを操作できる API を構築しました。詳細については、「[リゾルバーのマッピングテンプレートリファレンス](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
```