🦊

Amplifyで自動生成されたAppsyncリゾルバー(VTL)をカスタマイズする

2022/12/24に公開

こんにちは @kita3222 です👋
本記事は AWS AmplifyとAWS×フロントエンド Advent Calendar 2022、24日目の記事です。

はじめに

Amplifyはschema.graphqlの定義に基づいて、@model ディレクティブをつけたtypeについては全てリゾルバーを自動生成します。取得するデータをユーザーごとにフィルタリングする処理をバックエンド側で実施したい場合には、VTLをカスタマイズすることで実現できます。

今回は、こちらの記事でご紹介したLambda認証と組み合わせた場合の実装についてお話ししていきます。

Amplifyで生成されたリゾルバーを上書きする

Amplifyによって自動生成されたVTLはamplify/backend/api/<api-name>/build/resolversに定義されています。

この自動生成されたファイルの内容を上書きしていきます。今回は、先程作成したTodoモデルのレスポンスのVTLファイルを上書きしようと思います。

上書きしたいVTLファイルをコピペ

amplify/backend/api/<api-name>/build/resolversにあるQuery.listTodos.res.vtlファイルをコピーし、<project-dir>/amplify/backend/api/<api-name>/resolvers/にペーストする。

VTLファイルを編集

VTLファイルを編集していきます。
VTLのプログラミングガイドに則って、listTodosクエリーを実行した際に、ownerフィールドと認証用Lambdaから渡されたアカウントIDが一致するレコードにフィルタリングされるよう以下のように修正します。


## [Start] ResponseTemplate. **
- #if( $ctx.error )
-   $util.error($ctx.error.message, $ctx.error.type)
- #else
-   $util.toJson($ctx.result)
- #end

+ #set( $items = [] )
+ #foreach( $item in $ctx.result.items)
+   #if ($item["owner"] == $ctx.identity.resolverContext["accountID"])
+     $util.qr($items.add($item))
+   #end
+ #end
+ #set( $ctx.result.items = $items )
+ #if( $ctx.error )
+   $util.error($ctx.error.message, $ctx.error.type)
+ #else
+   $util.toJson($ctx.result)
+ #end

## [End] ResponseTemplate. **

認証用Lambdaのレスポンスを修正する

レスポンスの中にresolverContextを追加し、リゾルバーに渡すアカウントIDを定義する。

export const handler = async (event) => {
  const { authorizationToken } = event;
  
  // authorizationTokenを使って認証を行う
  // 外部認証システムで作成されたアカウントIDなど、アカウントごとに一意に発行される値を使用
  const getMyAccountId = () => 'myAccountId';
  const myAccountId = getMyAccountId();
  
  // 認証に成功した場合は isAuthorized をtrueで返す
  if (isAuthorized) {
      // リゾルバーに渡すaccountIDを定義する
      return {
        isAuthorized: true,
        ttlOverride: 300,
+	resolverContext: {
+	  accountID: myAccountId
+	}
      };
   // 認証に失敗した場合は isAuthorized をfalseで返す
   } else {
      return {
        isAuthorized: false,
        ttlOverride: 0,
      };
   }
}; 

amplify pushを実行してデプロイします。

動作確認

DynamoDBのTodoテーブルに以下3つのレコードを用意しました。

idが3のレコードのみ、ownerが異なります。

id name owner
1 test1 1234567890
2 test2 1234567890
3 test3 9999999999

そして、accountIDが123456789のユーザーがクエリーを実行すると以下のようになりました。

アカウントIDに一致するデータだけ取得するようフィルタリングされていました。

最後に

AmplifyでAppsyncのリゾルバ(VTL)のカスタマイズを行う方法をご紹介させていただきました。Amplifyでどうやるのかはわかっておりませんが、JavascriptでVTLを書く方法も最近だと出てきているようなのでそちらも今後は試していきたいと思います。

参考

https://docs.amplify.aws/cli/graphql/custom-business-logic/#override-amplify-generated-resolvers
https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/resolver-mapping-template-reference-programming-guide.html
https://dev.classmethod.jp/articles/using-javascript-for-graphql-api-resolvers-with-aws-appsync-samples/

PURPM MEDIA LAB Tech blog

Discussion