概要
AWS AppSyncはAWS上にGraphQLサーバーを構築することができるマネージドサービスです。
GraphQLの特徴の一つとして、取得するフィールドをクライアント側から指定することができる点があります。
GraphQLとネストされたフィールド
GraphQLスキーマでは、ある型のフィールドに他の型を指定することもできます。
type User {
name: String!
posts: [Post]
}
type Post {
id: ID!
content: String!
user: User!
}
このスキーマに適切にリゾルバーをアタッチすることで、
- Postとそれを作成したユーザーを取得
- ユーザーとそのユーザーが作成したPostの配列を取得
といったデータを1リクエストで要求できるようになります。
疑問点
上の例のようにUser
とPost
というモデルがあり、それをUserTable
とPostTable
というテーブルに別々に格納していたとします。
PostTable
にはuserId
という属性があり、これがテーブル間を結合する外部キーになります。
さて、ネストされたフィールドを含めてデータを取得するGraphQLクエリは以下のようになります。
query getPost {
getPost(id: "99999") {
id
content
user {
name
}
}
}
Post
はクエリの引数として与えられたid = 99999
で特定することができます。
しかし、Post
を作成したUser
はどのように特定すれば良いのでしょうか?
GraphQLスキーマには、あるフィールドを外部キーとしてマークする仕様はありません。
フィールドにリゾルバーをアタッチする
Post.user
がUser
型だから、userId
という名前で自動的にJOINしてくれる、ということはありません。
目的の動作を実現するには、Post.user
に対してリゾルバーをアタッチします。
リゾルバーのデータソースは、今回であれば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を使い始めるに当たって戸惑ったことがいくつかあるので、それらを少しずつまとめていけたらと思います。