Open4
AWS AppSyncを触った雑感想
はじめに
- 私はHasuraを利用しているのだが、AppSyncはよくHasuraと比較されるため以前から気にはなっていた
- 2023/2からHasuraのPricingが変更されたため、有料プランが従来の$99→$1.50/hour ($1,080/month)という料金になりめちゃくちゃ利用ハードルが上がった
AWS AppSyncとは
- 2018/4にGAになった、AWSのマネージドなGraphQL APIサービス
- Hasuraが設立されたの2017(ってどこかで見た)から、そのちょっとあとにGAになったのか
- マネージドサービスなので、自前でサーバ管理する必要はない
- DynamoDBテーブルやLambda関数などをデータソースとしたAPIを作成できる
料金
- リクエスト数単位での課金
- API Gatewayと同様のイメージ
- 別途EC2のインスタンス費用などは掛からない
- データソースにRDSやDynamoDBやLambdaを使っていたりしたら、それぞれ課金される
- 以下公式ドキュメントに書いてあった料金例
例) あるブログアプリケーションに月間 50,000 人のアクティブユーザーがいて、それぞれ 100 回の検索を実行するとします。検索によって毎月 5,000,000 件の AppSync クエリ操作が発生し、レスポンスサイズは平均 3 キロバイト (KB) です。
- クエリ操作料金 500 万回 × 4.00 USD/100 万操作 = 20.00 USD
- データ転送料金 3 KB × 500 万回 = 1500 万 KB = 14.3 GB × 0.09 USD = 1.29 USD
AppSync 料金の合計 20.00 USD + 1.29 USD = 21.29 USD
雑感想
- Hasuraは初期立ち上げのコストが圧倒的に低い
- Hasuraだと、接続したデータベースに変更を加えるだけでGraphQL schemaやresolverを生成してくれる
- 一方、AppSyncだと、
schema.graphql
を定義し、mapping templateを記述するっていうのは最低限必要- もちろんページングや集計クエリも自前で定義する必要あり
mapping templateとは?
client <-> query / mutation <-> mapping template(※コレ) <-> resolver <-> data source
- clientからのリクエストをresolverに渡すための変換処理が書かれたファイル
- VTL(Velocity Template Language)というテンプレート言語で記述する
- VTLはJavaで使われるテンプレートなので、AppSyncはJavaで動作していると想像...
- コード補完が効かないし、処理の共通化ができなかったりと辛そう
- 色々なブログみても、VTLはAppSyncのデメリットに必ず挙げられてる
VTL
たとえばこんな感じ。
mapping templateという名の通り、値の詰め替えやデフォルト値の設定なんかをする。
バリデーションチェックもここでやっても良い。
schema.graphql
type Task {
id: ID!
title: String!
description: String!
status: String!
createdAt: String!
updatedAt: String!
}
type Query {
listTasks(
limit: Int
nextToken: String
): ListTasks
}
Query.listTasks.request.vtl
#set( $limit = $util.defaultIfNull($context.args.limit, 10) )
#set( $ListRequest = {
"version": "2017-02-28",
"limit": $limit
} )
#if( $context.args.nextToken )
#set( $ListRequest.nextToken = $context.args.nextToken )
#end
#if( !$util.isNull($modelQueryExpression) && !$util.isNullOrEmpty($modelQueryExpression.expression) )
$util.qr($ListRequest.put("operation", "Query"))
$util.qr($ListRequest.put("query", $modelQueryExpression))
#if( !$util.isNull($ctx.args.sortDirection) && $ctx.args.sortDirection == "DESC" )
#set( $ListRequest.scanIndexForward = false )
#else
#set( $ListRequest.scanIndexForward = true )
#end
#else
$util.qr($ListRequest.put("operation", "Scan"))
#end
$util.toJson($ListRequest)
Query.listTasks.response.vtl
{
"tasks": $util.toJson($ctx.result.items),
"nextToken": $util.toJson($util.defaultIfNullOrBlank($context.result.nextToken, null))
}
- VTLは辛そうだけど、VTLさえ書けばDynamoDBへの出し入れはできてしまうというのは良い
- ちなみにこのVTLでデータソースと直接やりとりできるのはDynamoDBのみ
- それ以外のデータソース(RDSやOpenSearch)の場合は、Lambdaなどを挟んでデータベースとのCRUD処理を書く必要がある
- トランザクションが必要なmutationの場合は、データソースが何にせよLambdaなどで受けて処理する必要がありそう
- VTLの話は長くなるのでこのへんでおしまい
- ローカル開発環境は、Serverless frameworkの
serverless-appsync-simulator
が使える- Lambdaのローカル起動も
serverless-offline
というプラグインが使えるし、DynamoDBはserverless-dynamodb-local
があるし、Serverless framework便利や...
- Lambdaのローカル起動も
- LambdaだけならAWS SAMを使ってインフラ管理してデプロイするのが楽だけど、AppSyncには対応していなそうなので、Serverless frameworkを使うのが一番簡単そう
まとめ
- (あたりまえだけど)GraphQLサーバとしてどれを使うかは適材適所
- とはいえ既にAWSを使っていて、GraphQLサーバを立てたいときの第一候補にはなりそう
- リクエストベースの課金は非常にありがたく、AppSync + DynamoDB + Lambdaのようなアーキテクチャにすれば、かなりの低コストでGraphQLサーバを建てられちゃう
- Serverless flameworkのプラグイン (serverless-appsync-plugin, serverless-appsync-simulator) を使えば、ローカル開発やデプロイ周りも割と楽にできそう
- AWS CDK, CloudFormationでもインフラをコード管理できると思うが、ローカル開発の文脈でしんどそうなのでServerless使うのが良さそう
- 認証認可周りはまだ触ってないので、いつか試したい
- AWS Cognitoと連携することで開発体験的に楽になるのか