「Amplify Gen 2 ワークショップ」の補足の補足(2024/04/21)
Amplify Gen 2 ワークショップ
Gen2になってCDKとの統合がされたらしく、いつか触ってみたいと思っていた。
Amplify自体も結構前に1回触ったきりなので知識はほぼない。
実施したワークショップのリンク
Xで以下が流れてきたので、手を動かしてみるかーとなったところ。変更が結構あって躓く人が多そうだったのでメモ
参照の参照先も
ワークショップ実施前に確認すること
バージョンの話なので手戻りがないように
Node.jsのバージョン
ワークショップの手順をそのまま進めるとNode.jsのv20になってしまい諸々不都合なのでv18にする。
nvm install 18 # v18.19.0が入った
nvm use 18
npm install
amplifyのバージョン
手順だとbeta
になっているが、クイックスタートにはlatest
使ってたのでこっちにした。betaにして実施してても結局今のドキュメントと関数が変わってたりしてちょくちょくひっかかったので今のドキュメントベースで調べながら変えていく方向に。
npm create amplify@latest -y
ワークショップ中
データモデルのリレーションを定義
最初に引っかかったところ。以下を見て解決。
認可ルールを定義
public()がないと怒られた。あってるかどうかはわからないけど、ドキュメントを見て修正した。
specificGroup()も怒られるので同様に対処。
変更前 | 変更後 |
---|---|
public() | publicApiKey() |
specificGroup() | group() |
この時点のコード
import { ClientSchema, a, defineData } from '@aws-amplify/backend';
const retailStoreSchema = a.schema({
Product: a.model({
id: a.id().required(),
name: a.string().required(),
description: a.string(),
price: a.float(),
current_stock: a.integer(),
image: a.string(),
rating: a.float(),
style: a.string(),
category: a.belongsTo('Category', 'id'),
}).authorization(allow => [
allow.publicApiKey().to(['read']),
allow.owner(),
allow.group('Admin'),
]),
Category: a.model({
id: a.id().required(),
name: a.string().required(),
description: a.string(),
image: a.string(),
styles: a.string().array(),
products: a.hasMany('Product','id'),
}).authorization(allow => [
allow.publicApiKey().to(['read']),
allow.group('Admin'),
])
});
export type Schema = ClientSchema<typeof retailStoreSchema>;
export const data = defineData({
schema: retailStoreSchema,
authorizationModes: {
defaultAuthorizationMode: 'apiKey',
apiKeyAuthorizationMode: {
expiresInDays: 7,
}
}
});
サンプルデータをロード
サンプルデータのロードを実行しようとすると、undefinedで怒られる。
とりあえずサンプルデータをアップロードしてそうな部分を探すと以下がそれっぽい。
ファイルだと141行目あたりのところ
// 以前省略
// Load products
let numProducts: number = products.length;
if ( currProductCount !== numProducts ) {
console.log("Loading products");
let productCount: number = currProductCount;
localStatus["productProgress"] = ( productCount / numProducts ) * 100;
for (const prod of products) {
const { errors, } = await client.models.Product.create({
id: prod.id,
name: prod.name,
categoryProductsId: categoriesMap[prod.category].id,
current_stock: prod.current_stock,
description: prod.description,
image: `${SOURCE_BUCKET_URL}/images/${prod.category.toLowerCase()}/${prod.image}`,
price: prod.price,
style: prod.style,
rating: REVIEWS[Math.floor(Math.random() * REVIEWS.length)]
});
if ( errors !== undefined ) {
console.error(errors);
if ( errors[0].errorType !== "DynamoDB:ConditionalCheckFailedException" ) {
localStatus["productStatus"] = "error";
localStatus["productResultText"] = `Error loading products: ${errors[0].errorType}`
break;
}
} else {
productCount += 1;
localStatus["productProgress"] = ( productCount / numProducts ) * 100;
}
statusCallback(localStatus);
// 以下省略
ワークショップ上で変更したProductのデータモデルは以下なので、categoryProductsId
に差分がある。
Product: a.model({
id: a.id().required(),
name: a.string().required(),
categoryProductsId: a.string(),
description: a.string(),
price: a.float(),
current_stock: a.integer(),
image: a.string(),
rating: a.float(),
style: a.string(),
category: a.belongsTo('Category', 'id'),
}).authorization(allow => [
allow.publicApiKey().to(['read']),
allow.owner(),
allow.group('Admin'),
]),
amplify的に正しいのかとか、そもそもこのId自体がなんなのかよくわかってないが、categoryProductsId
を/RetailStore/amplify/data/resource.ts
に追加したら読み込めた。
Product: a.model({
id: a.id().required(),
name: a.string().required(),
+ categoryProductsId: a.string(),
description: a.string(),
price: a.float(),
current_stock: a.integer(),
image: a.string(),
rating: a.float(),
style: a.string(),
category: a.belongsTo('Category', 'id'),
}).authorization(allow => [
allow.publicApiKey().to(['read']),
allow.owner(),
allow.group('Admin'),
]),
サンプルデータから読み込まないように/RetailStore/src/utils/data-loader/loader.ts
を変更してもいいのかもしれない。
画像は読み込めてないけど変更箇所ではないのでヨシ!(最後まで行った後にURLを確認したらサンプルデータには恐らくデモ用のS3バケットの署名付きではないURLになってた。直接アクセスするとAccessDenied
なので無視でいいと思う)
全体のコード
import { ClientSchema, a, defineData } from '@aws-amplify/backend';
const retailStoreSchema = a.schema({
Product: a.model({
id: a.id().required(),
name: a.string().required(),
categoryProductsId: a.string(),
description: a.string(),
price: a.float(),
current_stock: a.integer(),
image: a.string(),
rating: a.float(),
style: a.string(),
category: a.belongsTo('Category', 'id'),
}).authorization(allow => [
allow.publicApiKey().to(['read']),
allow.owner(),
allow.group('Admin'),
]),
Category: a.model({
id: a.id().required(),
name: a.string().required(),
description: a.string(),
image: a.string(),
styles: a.string().array(),
products: a.hasMany('Product','id'),
}).authorization(allow => [
allow.publicApiKey().to(['read']),
allow.group('Admin'),
])
});
export type Schema = ClientSchema<typeof retailStoreSchema>;
export const data = defineData({
schema: retailStoreSchema,
authorizationModes: {
defaultAuthorizationMode: 'apiKey',
apiKeyAuthorizationMode: {
expiresInDays: 7,
}
}
});
ワークショップ終了後
Amplify プロジェクトを削除する
マネジメントコンソールが日本語になっている都合で削除の難易度が上がった。ハイコンテキストAWSユーザ力が求められる。
delete
で削除。
CloudWatch ロググループを削除する
引っかからなかったところではないけど一応。
/aws/lambda/amplify-retailstore-
を削除すると記載されてるけど、/aws/lambda/amplify-
でフィルターするとデプロイしたamplifyのIDのログがある。
その他にも/aws/amplify/<AmplifyのID>
や/aws/lambda/Cloud9-Cloud9
をプレフィックスに持つログがあるので任意に。
おわりに
amplifyの画面のドメインからアクセスができて、無事完走できた。
引っかからなかったところ
以下のGraphqlの作成エラーは自分の環境では再現しなかった。
ワークショップ自体の感想
Typescriptなのでamplifyの操作自体は割となんとかなりそうという感触。
一方で、後半からはワークショップでありがちなコードのコピペになってあんまり中身を理解しないまま進んでしまってる感が否めない…
特にForm Builder
以降が置いてかれている感があったので、誰かと一緒にワークショップやるといいんだろうなぁ
Discussion