Open19

AWS Amplify Gen1 を一通り使ってみてのメモ

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

Amplify のNext14ではSSR対応が不完全

https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/ssr-Amplifysupport.html
「Amplify が Next.js SSR をサポート」とか言ってるんだがよく読むと、、、

サポートされていない 機能

  • エッジ API ルート(エッジミドルウェアはサポートされていません)
  • オンデマンドインクリメンタル・スタティック・リジェネレーション (ISR)
  • 国際化 (i18n) 自動ロケール検出
  • Next.js ストリーミング
  • 静的アセットと最適化されたイメージでミドルウェアを実行する

とかしれっと言ってるので注意。特にNext.js ストリーミングはつまりSSR Streamingに対応してないので、Server componentsでSuspense が使えない。すごい悲しい、、、。GithubにIssue要望も上がっていることなので、そのうち対応してくれることを期待したい。現状はSuspenseしたければClient componentsに切り出してやりましょう、、、。下記の記事でいろいろ試してくれているので参考になりました。

https://zenn.dev/devcamp/articles/4a4e559d8544bc#3.-ssr-streaming-の機能

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

Amplify Studioは有効にしても良いが基本的に使うな

Amplifyの設定関連でAmplify Studioをつい使いたくなるかもしませんが、基本的にあそこで設定できることは全てAmplify CLIでやれるのでStudioは使わずCLIで設定しましょう。ユーザーの削除くらいしかあそこでやれることはないと思ったほうがいいです。どっちみちGen2ではStudioは無くなってるみたいだしね。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

実際はユーザーの削除もサービスとしてはフラグ管理で実際に消すことはないので、Studioつかってユーザー消すのは開発の認証周りをやってる時だけだったりはする。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

開発フローのベストプラクティス

これがなかなか難しい。とりあえずはGithubにmainとdevelopを作って、amplifyにdevとprodを作ってそれぞれを関連付けしてますがGItでPR作る前にPRを作る対象になるamplify のenvに対してamplify pushを行ってバックエンドの更新が確実にできるか?は確認したほうがいいです。この辺は何が良いのかわからないので難しい、、、。Gen2になるとSandbox機能が提供されると言うことなんですが、あまりイメージ湧いてない。。。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

Cognitoでユーザー情報を管理するとCognitoの上限に引っかかるかも知れない

なので、Userテーブルを別に切るわけですが、その場合にそのUserテーブルにいつユーザー情報を書き込むか?というと

https://wp-kyoto.net/amplify-clicognito-userpools-lambda-trigger/

この辺りの記事を参考に Post Confirmation でLambda関数をトリガーして、Lambda関数で良いようにUserテーブルにユーザーの初期情報を渡しておくといいと思います。これやるとCognitoは事実上ユーザー認証にしか使わないことになります。Userテーブル作ってそこから必要なユーザー情報を引っ張るほうが後々楽だった、、、

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

ある日を境にGraphQL Schemeの @function でinput型が効かなくなった

どう言うことや?と言う気持ちになったのですが、

https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/designing-your-schema.html

このへんにこれ

schema {
  query: Query
  mutation: Mutation
}

type Author {
  authorName: String
  Books: [Book]
}

input AuthorInput {
  authorName: String
  Books: [BookInput]
}

type Book {
  bookName: String
  Authors: [Author]
}

input BookInput {
  bookName: String
  Authors: [AuthorInput]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}

type Mutation {
  addAuthor(input: [BookInput]): Author
  addBook(input: [AuthorInput]): Book
}

input型ですが、当然 @functionしてるLambdaリゾルバを使ったMutationにも使える、、と思うんですが、実際はダメでした。ダメでした、と言うか途中からダメになりました。なんでや。探りに探ったのですが、結局わからなかったので直接Mutationに引数を書くことにして回避。なんでや。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

Client componentsでのauthMode: 'iam'でのAPI認証

authMode: 'iam' だけ書けばいけると思いきや、

import config from '@/amplifyconfiguration.json'
import { Amplify } from 'aws-amplify'

Amplify.configure(config, { ssr: true })

/src/app/layout.ts でやらないとならない。この辺は

https://zenn.dev/gentamura/articles/a9834076fcc101#amplify-ライブラリの読み込み

この辺りを参考に ConfigureAmplifyClientSide.ts を作ってlayout.tsで読み込んでやれば良いと思うのだがClient componetsやServer ActionなどでIAMで認証ができない(つまりUnauthorized userの認証をIAMで許可してるのに、APIがコールできない)場合には疑うと良いと思う。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

正直このシチュエーションは常にあるのに世の中のサンプルはAPIをunauthedなユーザーが叩く事を気にしてない内容の記事が多い。というかAWSのドキュメントにもないくらいなのですが、ブログひとつ作れねーじゃねーかそれじゃ。と言う気持ちになる。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

AmplifyやLambdaのtimezoneはUTC

で、これ変更できないので地味に面倒、、、。サービスによってはJSTで表示はしてくれたりとかあるけど、集計関連が絡む時に地味に面倒なので計画的にやりましょう、、、。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

ソーシャルログインの実装でSignIn/OutのRedirect URLを複数設定すると詰む

詰む、と言うか現状はCLIから複数設定できるにも関わらず正しくAmplify側では設定されない。Cognitoには設定が通るがdevとprodがある場合あまり意味をなさない。

実際にはAmplifyのフロントエンドのデプロイ時に環境変数を渡して、必要なredirectのURLを

config.oauth.redirectSignIn =
  process.env.NEXT_PUBLIC_OAUTH_REDIRECT_SIGN_IN || 'http://localhost:3000/auth/'
config.oauth.redirectSignOut =
  process.env.NEXT_PUBLIC_OAUTH_REDIRECT_SIGN_OUT || 'http://localhost:3000/auth/'

こんな感じで環境に合わせて設定する必要がある。Githubに要望は出てる(らしい)けど、どうやら現状は「仕様です」らしい、、、。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

ちなみにこれ、authしてるClient componentsで書かないとうまくいかない。layout.tsxとかで一箇所書いとけばいいやん、と思ってやったけどダメでした。なんでや?

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

Googleを使ったソーシャルログインでドメイン認証したいのでカスタムドメインをcognitoに設定した場合のAmplify側の設定

上記と似てるのだけど、これも普通に設定するとcognitoドメインをoauthのリダイレクトのURLに指定してくる(Amplify側で)。これを自分で明示的にCLIから設定する方法はない(はず)なので、これも環境変数でどうにかする。この時の oauth.domain で指定するのはhttps://がつかないやつなので注意。

if (process.env.NEXT_PUBLIC_OAUTH_DOMAIN) {
  config.oauth.domain = process.env.NEXT_PUBLIC_OAUTH_DOMAIN
}

カスタムドメインをCognitoに設定する方法はそれほど難しくないので割愛(DNSに指定したカスタムドメインをAレコードでエイリアスを有効にして他のレコードに紐づければよし)。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

AWS Backupの設定でAWSが出してる情報は微妙に舌足らず

とりあえずここを読むより、

https://github.com/aws-samples/aws-backup-amplify-appsync

こっち読んだほうが実務的には良いと思った。特に、、、

https://github.com/aws-samples/aws-backup-amplify-appsync?tab=readme-ov-file#project-setup

ここの認証周りの設定は見落とさずにやる。

あとはスクリプトがAWS CDKが v1 なので v2 にする必要がある(しなくても動くけど)。で、package.jsonで指定するnode moduleもv2対応にする。

https://aws.amazon.com/jp/blogs/storage/automate-backups-for-aws-amplify-graphql-backends-with-aws-backup/
https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/migrating-v2.html

Amplify側のドキュメントにもv2へのmigrationについてのドキュメンントがある。
https://docs.amplify.aws/javascript/tools/cli/migration/aws-cdk-migration/

で、AWS BackupではAWSの提供してくれているサンプルでも以下のパッケージも使ってるので忘れずに更新する。

    "@aws-amplify/cli-extensibility-helper": "^3.0.0",
Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

Amplifyの開発中にAPIKeyを使って開発するのは罠

APIKeyは長くて365日しか使えないし、プロダクションでは結局Cognito User Poolで認証ユーザーをIAMで非認証ユーザーの認証を行うことになるので、初めからその設定でやってdefault Authにはそのどちらかを設定してAPI Keyとは初めから縁を切っておいた方がいい。マジで。だってAPIKey更新できないんだもん(知ってる限り)。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

Amplify Studioで自動生成されるLambda関数のnodejsのversion 16のサポート終了の連絡が来たら

こんなメールが来る。

お客様の AWS アカウントに現在、Node.js 16 ランタイムを使用する AWS Lambda 関数が 1 つ以上あることが判明したため、ご連絡いたしております。

Lambda での Node.js 16 のサポートは 2024 年 6 月 12 日に終了します。これは、2023 年 9 月 11 日に Node.js 16 がサポート終了 (EOL) したことに続くものです [1]。

Lambda ランタイムサポートポリシー [2] で説明されているように、Lambda の言語ランタイムのサポートはいくつかの段階で終了します。2024 年 6 月 12 日以降、Lambda は Lambda 関数で使用される Node.js 16 ランタイムにセキュリティパッチやその他の更新を適用しなくなり、Node.js 16 を使用する関数はテクニカルサポートの対象ではなくなります。また、Node.js 16 は AWS コンソールで使用できなくなりますが、AWS CloudFormation、AWS CLI、AWS SAM、またはその他のツールを使用して、Node.js 16 を使用する関数を作成および更新することはできます。2025 年 2 月 28 日以降、Node.js 16 ランタイムを使用する新しい Lambda 関数を作成することはできなくなります。2025 年 3 月 31 日以降、Node.js 16 ランタイムを使用する既存の関数を更新することはできなくなります。

2024 年 6 月 12 日までに、既存の Node.js 16 の関数を利用可能な最新の Node.js ランタイムにアップグレードすることをお勧めします。Node.js 16 の関数のリストは、AWS ヘルスダッシュボードの [影響を受けるリソース](Affected resources) タブにあります。

サポートの終了は関数の実行には影響しません。関数は引き続き実行されます。ただし、これらはサポートされていないランタイムで実行されるため、AWS Lambda チームによるメンテナンスやパッチの適用は行われません。

で実際のLambda関数を見にいくと確かにnode16の関数がある、、、がこれAmplify関連の自動生成の関数だな、、、というわけで調べてみたら ↓
https://github.com/aws-amplify/amplify-studio/issues/1085

で、この中でリンクが貼られているドキュメントがこれ ↓
https://docs.amplify.aws/react/tools/console/adminui/access-management/#troubleshooting

あったあった。

To provide a passwordless login experience from AWS Amplify Console to Amplify Studio, Studio creates 4 Cognito Lambda triggers associated with the above-mentioned User Pool, named:
amplify-login-create-auth-challenge-SHORT_CODE
amplify-login-custom-message-SHORT_CODE
amplify-login-define-auth-challenge-SHORT_CODE
amplify-login-verify-auth-challenge-SHORT_CODE

これらのコードが確かにありました。で、これ何かと思ったらAmplify Studioに関したものでした。引き続きAmplify Studioを使うならoff/onしてもいいんだけど正直Amplify Studioを使う機会がほとんどない、何なら使うとトラブルの元になるのでオフにして関数が削除されて解決、、、。

Amplify Gen2がまだPreview版で仕事で使うのはちょっとな、と思うのですが早くGen2使ってみたいですね。Gen2はCLI Codeに一本化されてるし。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

amplify add authなりした時の登録確認メールの日本語化

cognitoに行けば書き換えられるんですが amplify update auth するたびにデフォルトに戻ってしまう。で、以下のように書くと、、、

 Specify an email verification subject: ああああ
 Specify an email verification message: いいいい {####} <br />うううう

cognito側ではこんな感じになる。

で、あれ改行が反映されてないじゃん、ってインターフェース的にはつい思ってしまうのだが、このテキストエリアの文言についてはHTMLでカスタマイズできる(と小さく書いてある)ので、見た目ばともかくとして最終的に送りたい文言をHTMLの改行である<br />を使ってまとめて書けば良い、ということになる。

ずっと「うまく反映されてないのでは、、?」と勘違いしていた。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

Cognitoから送信するユーザー作成時の確認メールのSESの設定

Cognitoを手作業でSESを使えるようにする(というかその前に必要なメールアドレスをSESに設定する必要があるが)と、何かの拍子で amplify update auth した時に設定がSESではなく開発時のCognitoがメールを送るものに戻ってしまう。で、これを固定する方法はないのか?と思ってたところ amplify override なるものがあることを知る。

Cognitoのメールを送信をSESで行うには以下のようにする。

amplify override auth

この時にcognitoのuserpoolを選択しておく。
で、SESのメール設定は割愛するが使えるメール設定がすでにあるとして、上記のコマンドで作成された custom.ts に以下のように記述する。

import {
  AmplifyAuthCognitoStackTemplate,
  AmplifyProjectInfo,
} from '@aws-amplify/cli-extensibility-helper'

export function override(
  resources: AmplifyAuthCognitoStackTemplate,
  amplifyProjectInfo: AmplifyProjectInfo,
) {
  resources.userPool.emailConfiguration = {
    emailSendingAccount: 'DEVELOPER', // SES使用を指定する場合はこれを設定
    from: 'no-reply <no-reply@example.com>', // Fromの表示設定はOptionだけど個人的にはしておいた方がいいと思う。
    sourceArn: 'arn:aws:ses:ap-northeast-1:xxxxxxxx:identity/no-reply@example.com', // SESで検証済みメールアドレスのarn
  }
}

amplify override auth ses あたりでググると情報が出てくるけど、こういうのが体系になってたり公式のドキュメントにまとまっていない(よね?)あたりがamplifyの使ってて辛いところではある。。。gen2になるとCLIではなくCDKでの設定になるので上記のような設定をリソースごとにしていくことになるので、まぁいくらか見通しは良くなるのかなぁ、、、と思ったりしてます。

あ、そうそう npm i @aws-amplify/cli-extensibility-helperもしておきましょう。

Hiroshi Yamato / dropcontrolHiroshi Yamato / dropcontrol

ブログの記事一覧、みたいなやつの管理画面を作ってる時にcreatedAtでソートしたいけど、データを取得する時にはソートキーがないと出来ない。で、記事ごとにステータスがある場合に enum が使える。
https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/graphql-types.html#enum-components

これを使えば、

enum EntryStatus {
  SCHEDULED
  OPEN
  CLOSE
}

type Entry {
~ 省略 ~
  entryStatus: EntryStatus
        @index(name: "EntryStatus", sortKeyFields: ["createdAt"], queryField: "entriesByEntryStatus")
~ 省略 ~
}

みたいなことができるのでステータス毎にソートして並べるとかはできる。id(@primaryKey)にソートキーでcreatedAtをつければいいじゃん。と思ったりするだろうけど、GSIとしてなんらかの値で絞り込みをかけた結果を記録していないとならないのでそれは出来ない(できるならぜひ教えて欲しいが、idをソートする、となると結局それってscanと変わらんじゃん?ということだよなぁ)。上の例だと entriesByEntryStatus というQueryをenumで指定した条件で絞り込んでそれをcreatedAtでソートすることが出来る。この辺はdynamoDBの戻り値が日付順とかで返ってくることを保証していない(と思う)のでどうにもならないところだと思う。

まーあとは戻り値をフロントエンドでソートする、という方法になるけどその辺は表示の量感にもよるだろうと思う。個人的にはステータス毎にタブを切り替える、みたいなUIにすればその方がスッキリするかな、と思うので、それはそれで良いのではないかと思っているが「全部一覧で見たい」となったらAppSyncが作成するlistを使うしかないだろう(Amplify Gen1でやれる範囲では)。