AWS AppSyncとReactでToDoアプリを作ってみよう (2)DataSourceとResolverの設定

## はじめに
前回の記事で定義したGraphQLスキーマはAPIのインターフェースの定義でした。
このインターフェースを使ってAPIにアクセスがあった際に、データを保存する先のリソース(DataSource)の作成と連携の部分を設定していきます。
AWS AppSyncでは、Resolverを作成することで、DataSourceとGraphQLスキーマとの紐付けを行います。

## リソース(DataSource)の作成

今回の例では、GraphQLスキーマに定義した`Todo`型からDynamoDBのテーブルを作成します。
まずは、コンソール画面から、「AWS AppSync > 作成したプロジェクト > Schema」を開き、画面右上の「Create Recources」をクリックします。

<img width="878" alt="CreateRecouces.png" src="https://qiita-image-store.s3.amazonaws.com/0/79414/5fc2852b-e2bb-c79a-f3bf-427db7557a78.png">

次の画面では、定義済みのGraphQLスキーマから使用する型を選択します。
今回は`Todo`を選択しました。

<img width="846" alt="スクリーンショット 2018-01-22 6.07.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/79414/475b2e15-ec39-01ec-1790-0ec3590b9507.png">

使用する型を選択すると、自動でテーブル名、テーブルの構成が入力されます。
今回は、idをプライマリキーとしました。

<img width="828" alt="スクリーンショット 2018-01-22 7.05.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/79414/45ff5d8d-62f1-1e7e-cfeb-0b7158200b72.png">


ここまでの項目を入力すると、画面最下部にテーブル定義を元に、自動で追加されるスキーマ定義のプレビューが表示されます。
最後に、「Create」ボタンをクリックすると、DynamoDBテーブルが作成されます。

<img width="835" alt="スクリーンショット 2018-01-22 7.05.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/79414/c9a08388-391c-f66e-d01c-27e06b229529.png">



## Resolverの追加と修正

前の手順では、GraphQLスキーマから自動でDynamoDBとResolverのプロビジョニングを行いましたが、一部、定義元のスキーマと紐付いていない点があるので、追加・修正していきます。

### getTodos
getTodosには、Resolverが紐付けられていないので、新規で追加します。

「Schema > Query > getTodos: [Todo]」の「Attach」をクリックします。
次の画面では、作成済みのDataSourceから紐付けるテーブルを選択します。
今回は`TodoTabe`を選択しました。

<img width="824" alt="スクリーンショット 2018-01-22 6.42.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/79414/d6848576-4ce2-71d2-095e-22c9648f74d7.png">

次に、リクエストのマッピングを行います。
「Paginated scan」のテンプレートをベースに、次のように変更しました。

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

レスポンスのマッピングは次のようになります。

```:ResponseMappingTemplate
$utils.toJson($context.result.items)
```

最後に、画面右下の「Save」をクリックしてResolverの設定を保存します。

### getTodo
これは、自動で追加されたQueryです。
今回のToDoアプリでは、item一件ごとに取得する`GetItem`操作は不要なので、削除します。

### allTodo
これは、自動で追加されたQueryです。
こちらは、getTodosと処理が重複するため削除します。
(ページネーション処理も自動で設定済みのようなので、こちらを使うのがよさそうですが...)

### addTodo
自動で追加されたMutation、`putTodo`の内容をこちらに移行すれば良さそうです。

```:RequestMappingTemplate
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key": {
        "id": { "S" : "${context.arguments.id}"}
    },
    "attributeValues" : {
        "id": {  "S": "${context.arguments.id}" },
		"title": {  "S": "${context.arguments.title}" },
		"description": {  "S": "${context.arguments.description}" },
		"completed": {  "B": "${context.arguments.completed}" }
    }
}
```

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

### updateTodo
updateTodoには、Resolverが紐付けられていないので、新規で追加します。
getTodosで行った新規追加手順と同様に操作を行い、次のテンプレートを設定します。

```:RequestMappingTemplate
{
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key": {
        "id": { "S" : "${context.arguments.id}"}
    },
    "update" : {
    	"expression" : "SET title = :title, description = :description, completed = :completed",
       	"expressionValues" : {
        	":title" : { "S": "${context.arguments.title}" },
          	":description" : { "S": "${context.arguments.description}" },
            ":completed" : { "BOOL": ${context.arguments.completed} }
       }
    }
}
```

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


更新操作は、DynamoDBの更新式の指定が必須となっているようでうです。



### deleteTodo
こちらは、自動でしっかりとマッピングされているので、そのまま使用します。

### putTodo
これは、自動で追加されたMutationです。
こちらは、addTodoと処理が重複するため削除します。

以上で、Resolverの設定が終わりました。


## APIの動作確認

作成したAPIの動作確認を行ってみます。
コンソール画面から、「AWS AppSync > 作成したプロジェクト > Queries」を開き、画面左側のエディターエリアにクエリを入力し「▶」をクリックしてクエリを実行します。

<img width="1086" alt="スクリーンショット 2018-01-22 22.37.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/79414/1fa543ad-7870-21f8-a427-5bd2efc3cbd9.png">


MutationとQueryそれぞれの項目を動作確認してみたいと思います。

### addTodo

まずは、データを追加してみます。

```:Query
mutation addTodo {
  addTodo(
    id: "0651ed86-9314-4267-9bcf-7143b785f173"
    title: "髪を切る"
    description: "来週までには"
    completed: false
  ) {
    id
    title
    description
    completed
  }
}
```

次のようなレスポンスが返ってくれば成功です。

```:Response
{
  "data": {
    "addTodo": {
      "id": "0651ed86-9314-4267-9bcf-7143b785f173",
      "title": "髪を切る",
      "description": "来週までには",
      "completed": false
    }
  }
}
```

### getTodos

事前に何件かデータを追加した状態で以下のクエリを実行します。

```:Query
query {
  getTodos {
    id
    title
    description
    completed
  }
}
```

```:Response
{
  "data": {
    "getTodos": [
      {
        "id": "f163372a-8b54-4da4-9237-911a64067517",
        "title": "豆腐を食べる",
        "description": "腐りそう",
        "completed": false
      },
      {
        "id": "0cbab86a-ad72-41b4-a63d-9ce3f9a7d552",
        "title": "Qiita書く",
        "description": "あと2本",
        "completed": false
      },
      {
        "id": "0651ed86-9314-4267-9bcf-7143b785f173",
        "title": "髪を切る",
        "description": "来週までには",
        "completed": false
      }
    ]
  }
}
```

## updateTodo

```:Query
mutation updateTodo {
  updateTodo(
    id: "0651ed86-9314-4267-9bcf-7143b785f173"
    title: "部屋を掃除する"
    description: "さらっと済ます"
    completed: false
  ) {
    id
    title
    description
    completed
  }
}
```



※ Responseは省略

## deleteTodo


```:Query
mutation deleteTodo {
  deleteTodo(
    id: "0651ed86-9314-4267-9bcf-7143b785f173"
  ) {
    id
    title
    description
    completed
  }
}
```

対象のitemのidを指定して、削除を行います。


※ Responseは省略

## 最後に

今回は、定義したGraphQLスキーマから自動でリソースを作成しましたが、AppSyncのコンソールからは、全て手動でリソースを用意することもできます。必要に応じて使い分けると良さそうです。
次回は、作成したGraphQL APIと連携するReactフロントエンドの実装を行っていく予定です。


## 参考

[Attaching a Data Source -AWS AppSync](https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/attaching-a-data-source.html)
[Provision from Schema -AWS AppSync](https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/provision-from-schema.html#aws-appsync-provision-from-schema)
[Resolver Mapping Template Reference for DynamoDB -AWS AppSync](https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/resolver-mapping-template-reference-dynamodb.html#aws-appsync-resolver-mapping-template-reference-dynamodb-updateitem)