更新
・2022/07/24 はまったこと の原因を記載
はじめに
これまで、API Gateway + Lambda + RDS(or Aurora Serverless)の REST API バックエンドしか実装したことがなかったのですが、いま参加している開発ではじめて AppSync + Aurora Serverless の GraphQL バックエンドを実装することになったので、色々調べならが実装中の、現時点の CDK のコードについて軽く紹介してみたいと思います。
本記事は、以下の記事の後続記事となります。
Aurora Serverless の CDK のコードについてご覧になりたい方は、こちらをどうぞ。
試した内容
利用したライブラリ
ライブラリ名 | バージョン |
---|---|
aws-cdk-lib | 2.25.0 |
@aws-cdk/aws-appsync-alpha | 2.25.0-alpha.0 |
- AppSync は、GraphQLスキーマとリゾルバ(VTLファイル)を分離して参照する形にしたかったので
aws-appsync-alpha
の方を試してみました。
実装コード例
ディレクトリ構成
.
└ lib
│ ├ api
│ │ ├ schema.graphql
│ │ └ resolvers
│ │ └ items
│ │ ├ get-items-req.vtl
│ │ └ get-items-resp.vtl
│ ├ stack
│ │ └ xxx-stack.tsx
GraphQL スキーマ
schemas.graphql
type Item {
id: ID!
name: String
}
type Query {
getItemss: [Item]
}
schema {
query: Query
}
- はじめてのお試しなので Model と Query だけ(Mutation はまだ未定義)
リゾルバー
get-items-req.vtl
## SQLステートメントの定義
#set ($statement = "SELECT * FROM item")
## リクエストテンプレートの定義
## @see https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/tutorial-rds-resolvers.html
{
"version": "2018-05-29",
"statements": [
$util.toJson(${statement})
]
}
-
SQLステートメントは複数行で整形して書くこともできる模様
AppSync Resolver multiline string · Issue #2331 · aws-amplify/amplify-cli -
version
って何のバージョンなのか、まだ未確認 -
入力データがある場合は、セキュリティ対策のためにサニタイズが必要ということだが、現時点では条件なしの一覧検索なので未確認
get-items-resp.vtl
## レスポンステンプレートの定義
## @see https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/tutorial-rds-resolvers.html
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
- 検索結果をそのまま返すだけなら、お作法に従うだけのよう
スタック
import * as rds from 'aws-cdk-lib/aws-rds';
import * as appsync from '@aws-cdk/aws-appsync-alpha';
/**
* Aurora Serverless をバックエンドに持つ AppSync GraphQL API の定義
* @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-appsync-alpha-readme.html
* @param scope
* @param cluster ★前回の記事で作成した Aurora Serverless のクラスター★
*/
const graphqlApi = (scope: Construct, cluster: rds.ServerlessCluster) => {
const api = new appsync.GraphqlApi(scope, 'GraphqlApi', {
name: 'GraphqlApi',
schema: appsync.Schema.fromAsset('./lib/api/schema.graphql'),
xrayEnabled: true,
});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const dataSource = api.addRdsDataSource('RdsDataSource', cluster, cluster.secret!, env.rdsDatabaseName());
dataSource.createResolver({
typeName: 'Query',
fieldName: 'getItems',
requestMappingTemplate: appsync.MappingTemplate.fromFile('./lib/api/resolvers/items/get-items-req.vtl'),
responseMappingTemplate: appsync.MappingTemplate.fromFile('./lib/api/resolvers/items/get-items-resp.vtl'),
});
return api;
};
- GraphqlApi
-
GraphqlApiProps
のschema
属性に、schema.graphql
ファイルから読み込んだスキーマ定義を指定します -
GraphqlApiProps
のauthorizationConfig
属性を省略すると、既定値は API キーによる認証モードが適用されます
-
- RdsDataSource の createResolver
-
BaseResolverProps
のtypeName
に GraphQL の操作種別(Query or Mutation)を指定します -
BaseResolverProps
のとfieldName
に、schema.grapql
で定義したクエリの名前を指定します -
requestMappingTemplate
、responseMappingTemplate
に、リクエスト・レスポンスそれぞれのリゾルバーファイルから読み込んだテンプレート定義を指定します
-
スタックのコードをみると、かなりスッキリと書けているかな。と思います。
API Gateway を OpenAPI Spec ファイルから作成するのと比べると、少しだけ色々書かないといけないようですが…
はまったこと
初回デプロイ時に AWSServiceRoleForAppSync の作成に失敗したように見える
14:16:46 | CREATE_FAILED | AWS::AppSync::GraphQLApi | GraphqlApiXXXXXXXX
Failed to assume service-linked role arn:aws:iam::xxxxxxxxxxxx:role/aws-service-role/appsync.amazonaws.com/AWSServiceRoleForAppSync, please retry. (Service: AWSAppSync; Status Code: 403; Error Code: AccessDeniedException; Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx; Proxy: null)
❌ XxxxStack failed: Error: The stack named XxxxStack failed to deploy: UPDATE_ROLLBACK_COMPLETE: Failed to assume service-linked role arn:aws:iam::xxxxxxxxxxxx:role/aws-service-role/appsync.amazonaws.com/AWSServiceRoleForAppSync, please retry. (Service: AWSAppSync; Status Code: 403; Error Code: AccessDeniedException; Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx; Proxy: null)
at prepareAndExecuteChangeSet (/xxxx/node_modules/aws-cdk/lib/api/deploy-stack.ts:385:13)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at CdkToolkit.deploy (/xxxx/node_modules/aws-cdk/lib/cdk-toolkit.ts:209:24)
at initCommandLine (/xxxx/node_modules/aws-cdk/lib/cli.ts:341:12)
The stack named XxxxStack failed to deploy: UPDATE_ROLLBACK_COMPLETE: Failed to assume service-linked role arn:aws:iam::xxxxxxxxxxxx:role/aws-service-role/appsync.amazonaws.com/AWSServiceRoleForAppSync, please retry. (Service: AWSAppSync; Status Code: 403; Error Code: AccessDeniedException; Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx; Proxy: null)
執筆時点では未解決の不具合のようです。
再デプロイすると正常動作するため、エラーが出たら再実行すれば動作します。
最後に
AppSync & Aurora Serverless の GraphQL バックエンドがちゃんと完成したら、もう少ししっかりした内容に更新しますぞ〜。
以上。