AWS
React
GraphQL
AppSync

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」をクリックします。

CreateRecouces.png

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

スクリーンショット 2018-01-22 6.07.41.png

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

スクリーンショット 2018-01-22 7.05.49.png

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

スクリーンショット 2018-01-22 7.05.59.png

Resolverの追加と修正

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

getTodos

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

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

スクリーンショット 2018-01-22 6.42.08.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」を開き、画面左側のエディターエリアにクエリを入力し「▶」をクリックしてクエリを実行します。

スクリーンショット 2018-01-22 22.37.05.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
Provision from Schema -AWS AppSync
Resolver Mapping Template Reference for DynamoDB -AWS AppSync