LoginSignup
9
6

More than 3 years have passed since last update.

AWS AppSyncで一対多の関連を1リクエストで取得する

Posted at

概要

AWS AppSyncはAWS上にGraphQLサーバーを構築することができるマネージドサービスです。
GraphQLの特徴の一つとして、取得するフィールドをクライアント側から指定することができる点があります。

GraphQLとネストされたフィールド

GraphQLスキーマでは、ある型のフィールドに他の型を指定することもできます。

GraphQLスキーマ
type User {
  name: String!
  posts: [Post]
}

type Post {
  id: ID!
  content: String!
  user: User!
}

このスキーマに適切にリゾルバーをアタッチすることで、

  • Postとそれを作成したユーザーを取得
  • ユーザーとそのユーザーが作成したPostの配列を取得

といったデータを1リクエストで要求できるようになります。

疑問点

上の例のようにUserPostというモデルがあり、それをUserTablePostTableというテーブルに別々に格納していたとします。
PostTableにはuserIdという属性があり、これがテーブル間を結合する外部キーになります。

さて、ネストされたフィールドを含めてデータを取得するGraphQLクエリは以下のようになります。

GraphQLクエリ
query getPost {
  getPost(id: "99999") {
    id
    content
    user {
      name
    }
  }
}

Postはクエリの引数として与えられたid = 99999で特定することができます。
しかし、Postを作成したUserはどのように特定すれば良いのでしょうか?
GraphQLスキーマには、あるフィールドを外部キーとしてマークする仕様はありません。

フィールドにリゾルバーをアタッチする

Post.userUser型だから、userIdという名前で自動的にJOINしてくれる、ということはありません。
目的の動作を実現するには、Post.userに対してリゾルバーをアタッチします。

AppSyncのフィールドにリゾルバーをアタッチ

リゾルバーのデータソースは、今回であればUserTableからデータを取得したいのでUserTableに対応するデータソースを指定します。
マッピングテンプレートはシンプルに一件アイテムを取得する命令を書けばOKです。

今回はデータソースにAmazon DynamoDBを利用しているので、以下のようになります。

リクエストマッピングテンプレート
{
  "version": "2017-02-28",
  "operation": "GetItem",
  "key": {
    "id": $util.dynamodb.toDynamoDBJson($ctx.source.userId),
  }
}
レスポンスマッピングテンプレート
$util.toJson($ctx.result)

ポイントはリクエストマッピングテンプレート中の$ctx.source.userIdの部分です。
この$ctx.sourceに、getPostクエリの実行結果が格納されているので、それを使ってUserTableにデータを取りに行きます。

まとめ

モバイルアプリ / SPAを開発していると、一画面で必要となる情報が複数モデルにまたがってリクエスト数が増えたり、それらをまとめた使い回しがききにくいエンドポイントを作ったりという課題が発生するかと思います。

GraphQLを使うことで、複数エンティティにまたがるデータの取得も非常にシンプルに実現することができます。

今までRESTを使っていて、GraphQLを使い始めるに当たって戸惑ったことがいくつかあるので、それらを少しずつまとめていけたらと思います。

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6