こんにちは!
今日も AppSync について元気に投稿していきます!今回はパイプラインリゾルバーについて解説していきます。気になっているけどまだ使ったことない方が多いのではないでしょうか。
AppSync で GraphQL 開発をされている方、AppSync に興味のある方はぜひこの記事をご活用ください。
AppSync のパイプラインリゾルバー、皆様すでに利用されておりますでしょうか?
要件によってはとても便利な機能となりますので、まだ触れていない方はこの記事でイメージをつかんでいただければと思います。ご存知の方も、CloudFormation のテンプレートなども記載しておりますので、ぜひ最後までご一読ください!
パイプラインリゾルバーとは、オペレーション(関数)を順番に実行できるAppSync の機能です。
まず始めに理解を高めるために、AppSync の GUI コンソール画面を見てみましょう。パイプラインリゾルバーがどんなものかイメージするのに役立ちます。
こちらはパイプラインリゾルバーの編集画面です。各セクションを確認してみると、以下のような流れになっています。
動作としては、パイプラインリゾルバーを実行する前にまず、Before マッピングテンプレートが実行され、そのあとに指定した順序で関数(Functions)が実行されます(画像でいうと、AppSyncDemoFuncConf1、AppSyncDemoFuncConf2 のところになります)。そして最後に、After マッピングテンプレートが実行され結果が返されます。
この一連の動きがパイプラインリゾルバーの仕組みとなります。
ここでの注意点としては、Before と After マッピングテンプレートはあくまで関数の前後に何かしらのロジックを実行する際に使われているだけになりますので、データソースへのアクセスはできません。データソースに対する操作などは、必ず関数(Functions)内で実行しましょう。
それでは次に、各セクションについて解説していきます。
実行前に何かしらのロジックを実行するところです。
一般的には、再利用することの多い情報の文字列をセットします。その際は、$ctx.stash を使って以下のように記述します。
$util.qr($ctx.stash.put("email", $ctx.args.input.email))
{}
上記は、実行されたクエリ内にある “email” の値を $ctx.args.input.email で取得し、$ctx.stash で使えるようにセットしています。セットされた値は、$ctx.stash.email などの変数名で利用することができます。
2つ以上の関数で共通の値がある場合などは、Before マッピングテンプレートの段階で $ctx.stash を利用してみると便利です。
CloudFormation では、以下のように記述します。
Resources:
PipelineResolver:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
TypeName: "Query" #required
FieldName: "getUserAndGroup" #required
Kind: PIPELINE
PipelineConfig:
Functions:
- !GetAtt FunctionConfigurationStep1.FunctionId
- !GetAtt FunctionConfigurationStep2.FunctionId
RequestMappingTemplate: | # Before マッピングテンプレート
$util.qr($ctx.stash.put("email", $ctx.args.input.email))
{}
ResponseMappingTemplate: | # After マッピングテンプレート
$util.toJson($context.result)
RequestMappingTemplate の部分が Before マッピングテンプレートの部分になります。なお、ResponseMappingTemplate の部分には After マッピングテンプレートを記述します。
パラメータ「Functions」は実行したい順番で、FunctionId を列挙しましょう。
ここは通常のリゾルバーと同じようにリクエストとレスポンスマッピングテンプレートを記述していきましょう。前の関数の結果は $ctx.prev.result で取得できますので、2番目以降の関数で必要な時に活用しましょう。
CloudFormation では、以下のように記述します。
Resources:
FunctionConfigurationStep1:
Type: AWS::AppSync::FunctionConfiguration
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource1.Name #required
Description: This is demo.
FunctionVersion: '2018-05-29' #required
Name: AppSyncDemoFuncConf1 #required
RequestMappingTemplate: |
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
}
}
ResponseMappingTemplate: |
$util.toJson($context.result)
FunctionConfigurationStep2:
Type: AWS::AppSync::FunctionConfiguration
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource2.Name #required
Description: This is demo.
FunctionVersion: '2018-05-29' #required
Name: AppSyncDemoFuncConf2 #required
RequestMappingTemplate: |
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.prev.result.groupId),
}
}
ResponseMappingTemplate: |
#if($ctx.error)
$util.error($ctx.error.message, $ctx.error.type)
#end
$util.qr($ctx.prev.result.put("groupName", $ctx.result.groupName))
$util.toJson($ctx.prev.result)
上記の例を解説すると、1番目の関数で DynamoDB から id を取得したあと、1番目で取得した id と同じ値の groupId を2番目の関数で取得し、1番目の結果と2番目の結果の中にある「groupName」の値をマージしたものを最終的な結果として返しています。
なお2番目の関数のレスポンスマッピングテンプレートのところでは、$ctx.prev.result.put を実行することで、2つの関数の結果をマージしています。
こちらは最終的なレスポンスを返すところになります。
関数のほうでデータ操作を十分に行っている場合がほとんどですので、単純にパイプラインの最後の関数の出力を返すように記述します。複雑な操作はとくに必要のないところになります。
$util.toJson($context.result)
パイプラインリゾルバーは、1つのクエリに対して複数のデータソースを扱う場合にメリットを発揮します。
データソースが DynamoDB の場合は、2つ以上のテーブルに対して操作が必要なときなどに利用する際に便利です。また Cognito においては複数のリゾルバーを実行することにより複雑な認可制御を実現できるでしょう。
ぜひこの機会に触れてみて、試してみてください!
パイプラインリゾルバーの仕組みがなんとなくでも分かりましたでしょうか?一見、複雑にみえてもリゾルバーを複数順番に実行しているだけですので、紐解いていけば理解は早くなるかと思います。このブログを機に理解を深めていただければ幸いです。
このブログでは、GraphQL や GraphQL のマネージドサービスである AWS AppSync の記事をどんどん公開しておりますので、ご興味のある方はほかの記事もご覧いただければと思います。
AppSync に関する開発は、お気軽にお問い合わせください。