re:Invent 2024: AWSフロントエンド開発最新機能 - Amplify・AppSync
はじめに
海外の様々な講演を日本語記事に書き起こすことで、隠れた良質な情報をもっと身近なものに。そんなコンセプトで進める本企画で今回取り上げるプレゼンテーションはこちら!
📖 AWS re:Invent 2024 - What's new in AWS for frontend developers (FWM311)
この動画では、AWS AmplifyとAppSyncのGeneral ManagerであるMohit SrivastavaとHead of ProductのNikhil Swaminathanが、フロントエンド開発者向けの最新機能を紹介しています。Amazon Q Developerを活用したコード生成、Amplify Gen 2によるフルスタックTypeScript開発、AppSync Eventsを用いたリアルタイム機能の実装など、具体的な機能をデモを交えながら解説しています。特に中古車販売アプリケーションを例に、AI会話型検索やリアルタイムオークション機能の実装方法、CloudWatch RUMとSyntheticsを使用した監視の設定まで、実践的なフルスタックアプリケーション開発の全工程を網羅的に説明しています。
※ 画像をクリックすると、動画中の該当シーンに遷移します。
re:Invent 2024関連の書き起こし記事については、こちらのSpreadsheet に情報をまとめています。合わせてご確認ください!
本編
AWS Amplifyとフロントエンド開発の概要
私の名前は Mohit Srivastava です。フロントエンドの Web およびモバイル開発者向けサービスの General Manager を務めています。具体的には AWS Amplify と AppSync を担当していますが、より広い視点で、関連する開発者向けサービスをフロントエンド開発者にとってより使いやすくする方法を検討しています。約20分後には、AWS Amplify の Head of Product である Nikhil Swaminathan と一緒にプレゼンテーションを行う予定です。本題に入る前に、手を挙げていただきたいのですが、Amplify または AppSync を使用したことがある方はどのくらいいらっしゃいますか?ライトが眩しくてよく見えないのですが、おおよそ半分の方が手を挙げているようですね。
まず初めに、皆様が素晴らしい re:Invent を過ごされていることを願っています。セッションから多くを学び、お互いから学び合い、お気に入りの新機能について議論されていることと思います。今年の re:Invent でフロントエンド開発者の方々とお話しできたことは、本当に身が引き締まる思いでした。スタートアップから大企業まで、お客様との対話を通じて、うまくいっている点や改善すべき課題について伺えたことは、非常に有意義でした。
それでは、開発者の皆様が、モダンなアプリケーションにおいてユーザーにとって重要だと考えていることについて、そしてそれが開発者のニーズや要件にどのように反映されているかについてお話ししていきましょう。その後、フロントエンド開発者に特に関連するサービスについて簡単に説明します。そして、時間の大半を実際のアプリケーション構築に費やします。アプリケーションを構築しながら、サービスについてさらに詳しく説明し、特に前回の re:Invent 以降、この1年間で発表された機能に焦点を当てていきます。最後に、私たちが構築したものを詳しく見て、その基盤となるアーキテクチャを検証していきます。
モダンアプリケーションにおけるユーザーニーズとフルスタック開発の進化
開発者の皆様がユーザーを代表して私たちに伝えてくることは何でしょうか?ユーザーは3つのことを求めています:高速なアプリケーション、魅力的なアプリケーション、そして信頼できるアプリケーションです。一般的に、これら3つを実現できれば、少なくとも適度に、できれば大きな成功を収めるアプリケーションになるでしょう。開発者が「高速」を求める場合、First Byte までの時間のような明白な要素もありますが、体感的なパフォーマンスも非常に重要です。例えば、ユーザーが UI を操作する際、サービスへの呼び出しに数秒かかる場合でも、UI がすぐに更新されることを確認する必要があります。逆に、サーバー側で更新が発生した場合、ユーザーの操作を必要とせずに、自動的なリアルタイム更新として反映されることで、体感的なパフォーマンスの向上につながります。
魅力的なアプリケーションに関しては、クロスプラットフォームやクロスデバイスの機能は依然として非常に重要です。しかし、この1年間の大きなトレンドは、開発者がアプリケーションをより魅力的にするために AI をどのように活用できるかということです。ユーザーは AI そのものには関心がなく、アプリケーションが単により良くなることを求めています。私たちは AI が主に2つの方法で使用されているのを目にしています。1つは実用的な洞察を導き出すことです。最近 Amazon.com を訪れた方なら、すべてのレビューを読む必要がなくなり、生成 AI がそれらを要約してくれるようになっていることをご存知でしょう。もう1つのユースケースは、UI を使用してワークフローを改善することです。典型的なユースケースは検索ボックスのような体験から始まりますが、一回限りではなく、AI エージェントとの双方向の会話を通じて、ユーザーが以前よりもはるかに速くタスクを完了できるようになっています。
信頼性とセキュリティは依然として最重要課題です。お客様にとって、これは認証の問題に集約されます。つまり、パスワードレス認証のような最新の標準をすべてサポートし、ユーザーにとってストレスのない認証を実現することです。認証後は、データのセキュリティとプライバシーの確保が重要となります。これらのお客様のニーズを見ると、フロントエンドだけの課題ではなく、フロントエンドとバックエンドの両方にまたがる作業が必要です。そのため、テクノロジーの革新に後押しされ、フロントエンド開発がフルスタック化していく進化を目の当たりにしてきました。
AWSのフルスタック開発サービスとAmplify Backendの紹介
最初の進化は、Serverlessの継続的なイノベーションです。Lambdaは今回のre:Inventで10周年を迎えましたが、この1年間で、Amazon BedrockのようなAIサービスやリアルタイムサービスに関して、Serverlessは大きな進化を遂げています。フロントエンド開発者向けのサービス提供が増えるにつれて、JavaScript側でも大きなイノベーションが起きています。
ReactやVueのようなフロントエンドフレームワークがフルスタックフレームワークへと進化しています。フルスタック化が進むにつれて、TypeScriptの成長も続いています。なぜなら、TypeScriptはフロントエンドとバックエンドの両方で型の安全性、予測可能性、正確性を提供してくれるからです。JavaScriptの人気が高まるにつれて、React Nativeも注目を集めています。興味深いことに、React Nativeが成長を続けるのか、それともFlutterのようなプラットフォームが台頭するのかという不確実性がある中で、開発者が同じJavaScriptコードベースをネイティブモバイルアプリにも使用したいという需要から、実際にはこの1年でReact Nativeのマーケットシェアは成長しています。
もちろん、最近のトレンドとして、開発者はこれらのコードをすべて一から書くのではなく、Amazon Q Developerのような生成AIソリューションを活用しています。これにより、CI/CDにおけるチーム間のコラボレーションも進化し、フロントエンドとバックエンドの2つの異なるデプロイメントループが1つのループに統合されています。フロントエンドとバックエンドのコードに非同期ワークフローがある場合、Observabilityソリューションもスタック全体をカバーすることが非常に重要です。フロントエンド、そしてフルスタック開発者にとって、今は非常にエキサイティングな時期です。これがこのスライドのまとめです。
これらの開発者のニーズとテクノロジートレンドに対応して、AWSはフルスタック開発のための多くのサービスを提供しています。Amazon Q Developerは開発者向けの生成AIアシスタントです。昨日も、Amazon Qに関する多くのエキサイティングな発表があり、本日はそれらについて詳しく見ていきます。また、AWS Amplify Backendと組み合わせて使用する方法も紹介します。Amplify Backendは、ユースケースに基づいてAWSバックエンドを定義する、非常に宣言的なコードファーストな方法を提供します。データストレージやAIなどの機能を備え、すべてCDKベースです。そのため、Amplify Backendでサポートされていない機能が必要な場合でもCDKを使用できます。今日はそれも見ていきましょう。
この演習でAmplify Backendを使用していく中で、実際には多くのAWSサービスをプロビジョニングしています。バックエンドAPIレイヤーにはAWS AppSync、認証にはAmazon Cognito、生成AIにはAmazon Bedrock、ストレージにはAmazon S3、そしてデータベースにはAmazon DynamoDBを使用します。 フルスタックのデプロイメントについては、Amplify Hostingについて説明していきます。これは完全マネージド型のホスティングサービスで、フロントエンドコードとCDKやAmplifyで書かれたバックエンドコードを、単一のデプロイメントループで一括してデプロイできます。
テストフェーズについては、他のセッションで詳しく扱われるため今日は触れませんが、AWS Device Farmは非常に優れたソリューションです。サイトがステージングまたは本番環境にデプロイされた後、実際のデバイスやブラウザを使用してテストを行うことができます。 最後に、可観測性についてですが、Amazon CloudWatchはエンド・ツー・エンドのソリューション群へと進化しています。今日はすべてを網羅することはできませんが、特にフロントエンド開発者にとって、CloudWatch RUMとCloudWatch Syntheticsは非常に強力です。CloudWatch RUMはユーザージャーニーのパフォーマンス、エラー、ユーザーモニタリングを提供し、Syntheticsはカナリアテストを提供します。これら2つの機能を組み合わせることで、エンド・ツー・エンドのフルスタック開発において非常に強力なツールとなります。
中古車販売アプリの構築:UIとAmazon Qを活用したドキュメント生成
それでは、今回作成するアプリを紹介しましょう。今日は中古車販売アプリケーションを構築します。リスティングや検索など、一般的な機能はもちろん備えていますが、ただの中古車販売アプリにはしたくありません。会話型検索や要約などのAI機能を実装し、さらにリアルタイムのオークション機能も追加します。売り手は、通常の固定価格での出品か、オークション形式での販売かを選択できます。これらすべてについて、NikhilとI私でロールプレイをしながら説明していきます。
典型的なフロントエンド開発者として、私はアプリの開発を始めています。まずTailwindを使用してUIを実装しました。まだバックエンドは接続していないので、モックデータを使用しており、いくつかのページを実装しました。一部のページのルーティングも実装済みです。 ここで最初の機能、開発者ドキュメントを生成できるAmazon Qの紹介に移りましょう。コメントがあまり充実していないコードを同僚のNikhilに引き継ぐ前に、少し手助けをしたいと思います。彼が始められるようにREADMEを生成したいと思います。そしてそれをAmazon Qを使って行います。
こちらが私のアプリで、VS Code IDEに切り替えてみましょう。左側に見えるのが私が始めたものです - ReactとNext.jsに詳しい方なら、かなり標準的な構成だとわかるでしょう。多くのUIコンポーネントがあり、それらのUIコンポーネントをいくつかのページにまとめています。右側のペインでAmazon Qを起動できます。 ここにはいくつかのオプションがあります。昨日リリースされたスラッシュドキュメント機能を選択しました。 既存のREADMEがない場合は新しく生成するか、既存のREADMEを上書きしたくない場合は更新するかを選択できます。今回は新しく生成することにします。
ここでは、完全に新しいREADMEを生成してみましょう。数秒で生成が完了し、包括的なREADMEができあがりました。 上部にはアプリケーションの簡潔な概要があり、その下には特殊な文字を使って、ファイル構造が見やすくコンパクトに視覚化されています。そして興味深いことに、特に注目すべきファイル、つまりアプリケーションの重要なファイルを指摘してくれています。これらのファイルのほとんどがページファイルなので、ページを重要なエントリーポイントとしてフラグを立てたのは理にかなっています。ただし、少し変わったファイルとしてconstants.tsにもフラグが立っていて、その理由が気になりました。
そこでこのファイルを開いてみると、確かに重要なファイルでした。見てみましょう。constants.tsは現在モックデータを使用しているため、 このアプリケーションのスキーマ、つまり構造を定義しているのです。そのため、重要なファイルとして強調されたのは納得できます。READMEマークダウンに戻ると、Nikhilにとって本当に価値のある興味深い指摘がいくつかあります。インストール手順や始め方の説明、 主要な機能について、そして設定や テスト、トラブルシューティングに関する説明が含まれています。
私が特に気に入っているのは、 データフローの部分です。コンポーネントとサポートコードが、アプリケーションの主要なデータフローにおいてどのように連携しているかを実際に説明してくれています。これで、コメントの少ないコードをNikhilに引き継ぐことに対する後ろめたさが少し和らぎ、彼も良いスタートを切れると思います。ありがとうございます、Mohit。Mohitは私の上司なので、実際にAmplify Gen 2を使ってアプリのバックエンドを構築するという重要な仕事を任されました。また、 ご覧いただけるように、そのプロセスではQ Developerも使用する予定です。
Amplify Gen 2とTypeScriptを用いたバックエンド開発
Gen 2をご存じない方のために説明すると、 今年5月に一般提供を開始しました。これはフルスタックアプリを構築するためのコードファーストの開発者エクスペリエンスを提供します。バックエンド全体をTypeScriptで構築できるようになりました。データもTypeScript、AIもTypeScript、ストレージも - お分かりいただけると思います。そして、AWS CDKの上に構築されているため、完全に拡張可能です。つまり、Amplifyバックエンドでネイティブに利用できない機能については、200以上のAWSサービスを追加できます。また、Gen 2はチーム向けに構築されており、開発者ごとのサンドボックスがあるため、チームの各開発者が互いに独立して作業を進めることができます。
フルスタックTypeScriptとは具体的に何を意味するのでしょうか?このビデオでは、左側にフロントエンドコード、 右側にバックエンドコードがあることを示しています。バックエンドに変更を加えるたびに、フロントエンドとの同期が取れなくなり、コンパイル時にエラーが発生します。これにより、 ビルド時間を待ったり、ビルド後に問題を発見したりするのではなく、コーディング中にエラーを検出できます。これこそが、Gen 2でTypeScriptを重視した理由です。
Moが私に渡してきたのは、UIが動作していて、始めるためのReadmeファイルが付いているアプリケーションです。これから私がやることは、データバックエンドを追加し、UIをそのデータに接続し、認証を追加し、AIを活用した会話型検索機能を追加して、そしてMoに戻して、ライブオークション、本番環境へのデプロイ、そして監視の設定を行ってもらうことです。
Amplify Gen 2を始めるのは、シンプルなNPMインストールコマンドで非常に簡単です。Car Tradingアプリが入ったプロジェクトでNPM create amplifyを実行すると、バックエンドにファイルが自動生成されます。ご覧の通り、ここにはamplifyフォルダがあり、その中にAuthとDataのリソースTypeScriptファイルがあります。Gen 2では、ファイルベースの規約アプローチを採用しており、すべてのバックエンド定義はこれらのリソースTypeScriptファイルで定義されます。
私たちは、これをインフラストラクチャ・アズ・コードというよりも、インフラストラクチャ・フロム・コードとして考えています。なぜなら、バックエンド定義の設定内容を定義するからです。デフォルトのスキャフォールドでは、メールでのログインが設定され、これをソーシャルサインインや多要素認証に拡張できます。データについては、Todoスキーマが定義されていますが、これはこの後すぐに修正していきます。これをデプロイすると、実際のAWSサービスがデプロイされ、認証用のCognito User PoolとIdentity Pool、データ用にはAPI層としてのAppSync、DynamoDBテーブル、そしてオプションでLambda関数も利用できます。
このファイルのデフォルトのTodoスキーマは私のニーズに合わないので、車両リストのスキーマを作成したいと思います。ここでListingと入力すると、TypeScriptなのでタイプ補完が効いて、モデルを作成できます。Qが実行されているので、たくさんのフィールドが提案されますが、これらのフィールドはMohitが見せてくれたReadmeに基づいた正しいフィールドではありません。通常なら、モックデータを含むコードベース全体を確認して、すべての異なるタイプでスキーマを更新する必要があります。
少し面倒くさいので、私は親しみやすいAIアシスタントのAmazon Qを開きました。これからプロンプトを書いていきます。このスキーマは完全に型付けされており、デプロイすると実際のAWSサービスがデプロイされます。
このPromptを見てみましょう。私がこのPromptに入力しているのは、データモデルの参考になる可能性のあるモックデータが/appフォルダと/componentsフォルダにあるかどうかを確認するようQに依頼するメッセージです。Amazon Qは最近、チャットがコードベース全体にアクセスできるWorkspaceディレクティブを導入しました。これにより、適切な情報がどこにあるかを特定できるようファイルをスキャンすることができます。また、Qの精度を更に向上させるために、Markdownファイルやカスタムプロンプトを含むDocsフォルダも公開しています。これらはすべて公開ドキュメントで利用可能です。
これを送信すると、QはCar ListingモデルとSellerモデルを生成します。ご覧の通り、SellerモデルはCar Listingsと1対多の関係を持っており、これは理にかなっています。また、誰が何にアクセスできるかを定義する認可ルールも設定されています。
ご覧の通り、ここでは定義したルールを使用して構文を強化するための要約も提供されています。 スキーマについては、検索結果からCar Listingのモックデータを見つけ、それを元にListingスキーマを作成しました。バージョン1では、シンプルに保つためにCar Listingに焦点を当て、Sellerモデルは除外することにします。
結果を生成して、これ全体をresource.tsファイルにコピーして何が起こるか見てみましょう。TypeScriptの利点の1つは、これを貼り付けた時に問題がすぐに分かることです。チャットでコードをコピー&ペーストできるこの体験は、ビルド時ではなくコンパイル時にエラーを捕捉できるTypeScriptとの相性が良いのです。ご覧の通り、19行目にphotosフィールドがあり、dot arrayは実際には存在しません。 ドキュメントを確認しなくても、補完機能を使用してstringを入力し、stringのarray型フィールドを使用できます。
間違っていた箇所を簡単に修正できました。次は認可ルールを見てみましょう。認可は誰が何にアクセスできるかを定義するもので、Amplifyスキーマでは非常にシンプルな方法でこれを行うことができます。ここでのルールを見ると、ownersつまりサインインしてデータを所有するユーザーが操作を実行できると書かれています。これは正しそうですが、ゲストユーザーが読み取り、作成、削除できるようになっていることに気付きました。ゲストにリストの作成や削除を許可したくないので、それを削除します。これでデータスキーマの準備が完了しました。
AI機能の実装:Amplify AI kitとAppSync Eventsの活用
それでは、デプロイの方法について学んでいきましょう。先ほど説明したように、Gen 2にはCloud Sandboxesという概念があります。これは、バックエンド用のnpm run devのようなものだと考えています。つまり、チームの各開発者が他のメンバーと独立して作業を進められ、並行作業中にモード変更が競合する心配がないのです。イテレーションの体験は、フロントエンドでの作業とよく似ています。Sandboxから始めて、フロントエンドの編集を行い、data resource.tsを更新すると、フロントエンドのコードは保存時に更新されます。データベーステーブルが追加され、フロントエンドと同じように、保存するたびにUIの変更がすぐに反映されるのです。
実際のデプロイ体験を見てみましょう。NPX Amex sandboxを実行すると、CloudFormationを使用したデプロイメントが開始されます。最初のデプロイメントは、アートとデータをデプロイするため数分かかります。ただし、特にデータスキーマについては、通常数分かかるデプロイメントを数秒で完了できるように最適化しています。デプロイメントが完了すると、デプロイしたリソースを定義する多くのリソース識別子が表示されます。
イテレーション体験を実際に見ていただくために、新しいフィールドを追加してみましょう。スキーマに移動して、車の状態を示すconditionフィールドを新しく追加します。保存すると、Sandboxが自動的にファイルの変更を監視しているので、デプロイメントは自動的に行われます。通常、デプロイメント中に、フロントエンドコードの更新作業を行います。デプロイメントにかかる15秒程度はほとんど気にならず、フロントエンドコードの編集を終える頃には、その変更がすでにクラウドにデプロイされているでしょう。
バックエンドをデプロイしたので、次はUIを今デプロイしたデータベースに接続する必要があります。
search-results.tsxファイルを開くと、3つのモックリスティングがあることがわかります。データベースには既に16件のレコードを含むシードデータを生成済みです。ここで、Amazon Qを使用してこのファイルを更新し、データに接続するために必要なコードを生成していきます。Amazon Qは常にウィンドウ内のファイルのコンテキストを把握しているので、ファイルを確認して更新を提案してくれます。
このファイルには多くの更新がありますが、Amazon Qの優れている点の1つは、主要な変更点について説明してくれることです。主な変更点を見ていくと、まず、データベースと通信できるようにクライアントを初期化するためのAmplify設定とクライアントのセットアップが追加されています。モックのリスティングを、client.list関数を使用した実際のデータに置き換え、実際のデータとやり取りするようになったため、ローディング状態の管理を追加しました。また、すべての状態の型をモックの型から実際の型に更新し、UIにローディングインジケーターを追加しています。
これは大きな変更なので、私の好みとしては、一括で変更するのではなく、コンポーネントの部分ごとにコピー&ペーストで対応していきたいと思います。まず、importを取り込んで、それが正しいことを確認します。コードのこの最初の部分で、importが問題ないことを確認します。 次に、データベースと通信できるようにAmplifyクライアントを初期化します。エラーがないので、問題なさそうです。次に、アプリケーション内のuseStateフックを更新して、このモックリスティング配列のコンテンツを置き換えていきます。
ご覧のように、listingsのuseStateフックは、data resource.tsで定義した実際のCarListingスキーマを使用するようになりました。型を見ると、すべての型情報が利用可能で、make、model、year、price、 data resource.tsで定義したすべての情報が確認できます。また、useStateフックでローディング状態を管理する必要があるため、loading stateも追加されています。
次はuseEffectの部分です。useEffectはページが読み込まれるたびに呼び出されるので、このuseEffectをアプリケーションにコピーします。setLoadingから始まり、データベースからcar listingsを取得し、そしてリスティングにソートを適用しているのが分かります。最初の段階ではこのソートは必要ないので、シンプルに保つために削除します。いくつかの変数を修正する必要があるので、それを行います。 それから、Amazon Qのインラインチャットを使用して、 car listingでエラーが発生した場合のconsole.logを生成し、クライアントでエラーをキャッチできるようにします。
ここまでは良さそうですが、フロントエンドのコードがあまり見栄えが良くありません。アプリケーションに簡単にコピー&ペーストできるものが欲しいので、Amazon Qに再度このUIコードを生成してもらい、ローディング画面があることを確認し、returnブロックを適切なコードで置き換えられるように、コピーしやすい形式にしてもらいます。Amazon Qがそれを生成したので、そのままコピーします。また、何を行ったのかの概要も示してくれます。 loading state、empty state、results stateを処理しているようです。これを貼り付けて、 エラーがないか確認してみましょう。
このファイルには現在2つのエラーがあるようです。これらを修正していきましょう。1つ目は単純な構文の問題で、2つ目はResultsViewコンポーネントがまだモックデータを参照しているため、型の不一致が起きています。そのコンポーネントを開いて修正していきましょう。7行目を見ると、フェイクの型、つまりモックインターフェースを使用しているのが分かります。そこで、data resource.tsファイルから実際のスキーマを使用し、インターフェースを更新して実際のスキーマを使用するようにしましょう。
ライブオークション機能の追加とAmplify Hostingによるデプロイ
Search Resultsファイルに戻ると、TypeScriptはもう問題を指摘しなくなりました。
Data Clientには、リアルタイムのサブスクリプションを可能にするObserved ClientやObserved Query機能など、他にも多くの機能があります。リスティングがUIに自動的に表示されるようにしたい場合は、リアルタイム機能を追加できます。また、ネットワークリクエストを最適化するために、Selection Sets、フィルター、ページネーションを使用することもできます。
データを取得してUIにデータを接続できたので、NPMのデフォルトスカフォールドを追加する方法を見ていきましょう。Create Amplifyはすでにメールでのログインを作成していますが、TypeScriptの経験を活かして、Amazon、Google、Facebook、Appleなどの外部プロバイダーを追加できます。多要素認証や、Amazon Cognitoの新しくリリースされたパスワードレス認証などの機能を追加し、データと同じようにデプロイすることができます。
デプロイが完了したら、ログインUIの作成を始めることができます。まず、Next.jsのApp Routerを使用して新しいログインルートとログインページを作成しました。今回はQ Chatを使用する代わりに、私たちが提供しているUIコンポーネントであるAuthenticatorを使って手作業で作成してみようと思います。コードは数行しかないので、Q Chatは必要ないと思いますが、Qはインラインで提案をしてくれるので、タブを押すだけで何を入力すべきか教えてくれます。
基本的に、私はAmplifyクライアントを再初期化しているところで、outputsから設定情報を取得して、もう一度configureを呼び出しています。Qは私が必要とする操作に基づいて推奨事項を提案してくれています。configに小さな構文エラーがあることに気づき、それを修正しようとしています。次に、ルートの関数を書こうとしています。ご覧の通り、Qが必要なコードを自動的に提案してくれたので、タブを押すだけで、これで始めるには十分だと思います。
これはAuthenticatorコンポーネントなので、ブラウザに戻ると、1分もかからずにサインインとサインアップのフローが完成しています。これにいくつか調整を加えようと思います。Authenticatorでユーザーコンテキストを取得して、サインイン時にテスト用にユーザー情報を確認できるようにします。すでにCognitoにユーザーを作成してあるので、Cognitoを確認すると、そこにユーザーが存在することがわかります。
サインインして、これが機能することを示したいと思います。ご覧の通り、ユーザーとしてサインインされており、サインアウト時には再びAuthenticatorが表示されます。次に私がやりたいのは、Authenticatorを編集して、アプリケーションの全体的な外観に合わせて、すべて黒色にすることです。そこで、テーマを実際に編集できるUIテーマコンポーネントをインポートします。
ここでも、入力時にQに推奨事項を提案してもらおうと思います。まずtokensを作成し、次にthemeオブジェクトを提案してくれて、これらが編集したいtokensかもしれません。私が本当に編集したいのはプライマリカラーだけで、とりあえず合わせるために黒に変更する2、3個の異なるtokensがあることを知っています。次に、AuthenticatorをTheme Providerコンポーネントでラップします。これで完成です。アプリケーションの他の部分と同じルック&フィールになり、ソーシャルログインなども非常に簡単に追加できます。そのためのpropsの種類が用意されているので、この場合、ソーシャルプロバイダーを追加したい場合は、social providersプロップを追加して、Amazon、Apple、GoogleやFacebookなどを追加するだけです。
これで、わずか数行のコードでバックエンドのデプロイ、UIコンポーネントの実装を行い、このフルスタック機能を動作させることができました。次は、新しくリリースされたAmplify AI kitを使用して、アプリケーションにAIパワーの会話型検索エクスペリエンスを追加する部分に進みましょう。
Amplify AI kitは、先ほどデータで見たのと同じTypeScriptベースのエクスペリエンスをAIに適用し、AIを活用した機能を素早く構築できるようにします。LLMにデータへの安全なアクセスを簡単に提供でき、それらはすべてバックグラウンドで処理されるため、機密性の高いユーザー情報がLLMに漏洩する心配がありません。これにより、2つのユースケースが簡単になります。1つ目はチャットと会話型検索の構築、2つ目はワンショット生成です。要約や画像生成などのユースケースでは、ビルトインのツールサポートも提供しており、LLMが外部APIを呼び出してデータを取得し、そのコンテキストをLLMに提供することができます。
実際に見てみましょう。 まず最初に、新しいルートを定義します。datasource.tsファイルにデータ定義があり、ここにconversationルートと呼ばれるものを追加します。conversationルートは、asyncがLLMと通信できるようにする新しい非同期ルートです。 この場合、BedrockとそのClaude 3.5 Sonnetモデルを使用しています。Bedrockで利用可能な任意のモデルを選択でき、型補完でそれらが提供されます。Haikuを使用したい場合はHaikuを使用できますし、re:Invent以降は新しいNovaモデルも追加される予定です。このシステムプロンプトでLLMに必要な情報を編集できるので、より文脈に応じた内容に編集できます。具体的にデータツールを使用すると、car listingモデルを参照できるため、ユーザーが情報を検索する際にLLMが使用できるように、リストに関する情報を提供できます。
バックエンドの設定が完了したので、フロントエンドのチャットルートを設定しましょう。 AI kitでは、AIフックを提供しています。この場合、AI conversation hookがUI会話フックを提供します。メッセージやメッセージ履歴などが提供され、 独自のUIを構築する場合に備えて、永続性が組み込まれているためソートやフィルタリングが可能です。また、AI conversation UIコンポーネントも用意されており、すぐに使えるUIコンポーネントを提供します。メッセージとメッセージレンダラーが用意されています。 React markdownレンダラーを使用することで、チャットを適切にレンダリングできます。これらのローディング状態により、チャットとのやり取り時にローディング状態を表示でき、handle send messageは事前に構築された関数です。
実際に動作を確認してみましょう。「西海岸で利用可能な車を探してください」とテストしてみます。 これによりasyncが呼び出され、Bedrockを起動し、Claudeからレスポンスを受け取ります。メッセージを見ると、 car listingツールにアクセスできることがわかり、 西海岸で利用可能な特定の車両に関する情報がまもなく提供されます。 現在返されている車両は、データベースからの実際の結果です。Tesla Model YやPorscheなど、データベースで利用可能なすべてのデータが表示されています。
これをさらに拡張することができます。会話型UIが組み込まれているため、アプリケーションのコンポーネントをLLMに提供することもできます。 この場合、car cardコンポーネントをresponse componentプロップを通じて渡すことができます。LLMが単なるテキストを返すのではなく、UIコンポーネントを返すリッチなインタラクションを構築できます。 generationルートは少し異なり、よりシングルショット型です。つまり、要約を生成したい場合や画像を生成したい場合も、useAIGeneration hookを使用して実現できます。この例では、generate car listing関数があり、新しいリストを作成するユーザーのために、選択されたフィールドに基づいてcar listingを定義するプロンプトを渡しています。
これらのユーザーのために、AI生成ボタンを含むUIを提供します。このボタンを使えば、LLMsを使ってアプリケーションの説明文を簡単に生成できます。ボタンを1回クリックするだけで、生成ルートを使用して説明文が生成されるのがお分かりいただけると思います。ここではデモできない追加機能もあります。独自のデータを持ち込んだり、ナレッジベースに接続したり、マルチモーダル検索のような機能も利用できます。
これら3つの機能を追加したところで、最後に追加するのはライブオークション機能です。しかし、その前に、これまで見てきた様々な機能をまとめてみましょう。READMEを生成するための/doc機能を見ました。/reviewについては見ていませんが、Amazon Qの/reviewは開発中のセキュリティ脆弱性や品質の問題を検出するのに役立ちます。機能開発について話す際には/devをデモします。@workspaceはコードベース全体へのチャットアクセスを提供し、インラインチャットはコーディング中にポップオーバーチャットのように使える新機能です。Amplify Backendについては、すべてのデータストレージ機能にわたって多くの新機能があります。Authでは、最近データを使用したパスワードレスサポートを開始しました。既存のPostgreSQLやMySQLデータベースを取り込むことができます。Storageでは、Dropboxのようなインターフェースで管理画面を構築できるStorage Browser UIコンポーネントがあり、Functionsではcronジョブや長時間実行タスクに関する機能があり、ログを直接サンドボックスにストリーミングすることもできます。
お客様がAmplify Backendを選択する主な理由は、インフラストラクチャをコードから取得でき、より迅速に出荷して顧客により早く価値を提供できるからです。ここで、AppSync Eventsを使用したリアルタイム機能の追加について、Mohitに戻したいと思います。AppSyncをご存知の方は、数週間前までAppSyncはGraphQLサービスに特化していたことをご存知でしょう。AppSync Eventsと呼ばれる新機能をリリースし、これによって純粋なWebSocketsを使用して、AppSyncが持っていた同じサブスクリプション機能を活用できるようになりました。
CloudWatchを用いたアプリケーションの監視と分析
その前に、オークション用のユーザーインターフェースをさらに追加してみましょう。/devコマンドを実行します。/devはNikhilが示したものとは異なり、複数のファイルを生成します。コードベースを解析して複数のファイルを生成します。私は/devに、オークションリストをサポートするようにUIを更新し、モックデータでテストページを提供するよう依頼しています。複数のパスで計画を立て、その計画を実装していきます。ここでは6つのファイルをレビューし、このユースケースでは何も更新せず、代わりに3つの新しいファイル(ページファイルとUIコンポーネント2つ)を作成することを決定したことが分かります。これを受け入れるか、まだ適切でないとしてフィードバックを与えてやり直すかを選択できます。今回は受け入れることにします。
確かに、返ってきた結果はかなり良好です - Nikhilが持っていた販売ページのように見えますが、右側にオークションリストウィジェットが追加されています。もちろん、これはすべて静的なものです。足りないのは、これをリアルタイムで更新したいということです。例えば、このTesla S(この価格だとPlaidモデルに違いありません)の開始入札価格が125,000ドルの場合、入札がリアルタイムで更新されることを望んでいます。では、AppSync Eventsを使用してどのようにそれを実現できるでしょうか?AppSync Eventsは完全なサーバーレスWebSocketsを提供します。これらは以前からAppSyncが持っていた機能ですが、GraphQLの背後に隠れていたものを、今では第一級のWebSocketsとして利用できます。数分でリアルタイムエクスペリエンスを作成でき、サーバーレスなので運用上のオーバーヘッドを気にする必要がありません。ポーリングのような代替手段と比較して、はるかに高速で、総コストを削減できます。
まず視覚的に見ていきたいのは、とてもシンプルなことです。 オーディエンス、つまりModel 3やModel S Plaidに入札する人々は、裏側では単にNamespaceとTopicにパブリッシュしているだけです。この場合はAuction IDを持つauctionsです。アーキテクチャ的には2つの選択肢があります:クライアントが直接これを行うか、あるいはこのアプリケーションではより理にかなっているのは、APIを通してサーバーに送り、サーバーがそれを処理する方法です。
サブスクリプション側では、そのNamespaceとTopicをサブスクライブできる補完的なAPIがあります。 コーディングの観点から見ると、パブリッシュは純粋なHTTP、サブスクライブは純粋なWebSocketsを使用します。もちろんブラウザから直接実行することも可能です。その方法については詳細なドキュメントを用意しています。あるいは、Amplifyクライアントライブラリの一部として作成したクライアントを使用することもできます。ご覧の通り、本当にシンプルで、任意のJSONを1行のコードでパブリッシュでき、サブスクライブも数行のコードで実現できます。
さて、アプリを構築し終えたので、デプロイして動作を確認してみましょう。 Amplify Hostingについて簡単にご紹介させていただきます。Amplifyのホスティング部分を使用したことがある方はどれくらいいらっしゃいますか?手を挙げていただけますか。少なめですね。Amplify Hostingの基本的な考え方は、静的アプリケーションとSSRアプリケーションの両方のソースコードを提供するだけでいい、というものです。ソースコードを提供する代わりに、アプリはグローバルにホストされます。カスタムドメインの設定も簡単で、バックエンドとフロントエンドの継続的デプロイメントが可能で、フィーチャーブランチも自動的に作成されます。つまり、GitHubの各ブランチが独自のサブドメインになり、アプリケーション内の認証とは別に、基本的な認証をオプションで有効にすることができます。
Amplify Hostingの本当にユニークな点は、SSRだけでなく、バックエンドにまで拡張される点です。この場合、devフィーチャーブランチをソース管理にチェックインすると、デプロイされるのは静的アプリケーションやSSRアプリケーションだけでなく、バックエンドも含まれます。実際の動作を見てみましょう。とても簡単です。コンソールで、好みのソース管理リポジトリを選択できます。 数週間前には、S3バケットを指定する機能もリリースしましたが、どちらでも問題ありません。今回はGitHubを使用します。 GitHubリポジトリの一覧を表示して、ブランチを選択できます。ステージング、プレプロダクション、プロダクションのデプロイメントを行いたいので、バックエンドのフィーチャーブランチを選択します。 ご覧の通り、これが単なるSSRアプリケーションではなく、バックエンドも備えたSSRアプリケーションだと認識されています。
数ヶ月前、スマートなデフォルト設定とターンキーソリューションという考え方を発展させ、最適化されたキャッシュポリシーもスマートなデフォルト設定とともにリリースしました。基本的な考え方は、アプリケーションを解析し、コンテンツタイプに基づいて判断を行うというものです。いずれにせよ、キャッシュ期間は最大1年間で、サイトの新しいバージョンをデプロイすると、キャッシュは無効化されます。静的コンテンツの場合、定義上同じ静的コンテンツになるため、キャッシュビューはCookieとクエリ文字列を無視するようにします。SSRコンテンツ、APIルート、リバースプロキシは正反対で、クエリ文字列、Cookie、特定のヘッダーを考慮する必要があります。これらがページの特殊なレンダリングを引き起こす可能性があるためです。
画像の最適化は中間に位置します。画像の最適化では、クエリ文字列によって提供される画像のサイズが決定されるため、キャッシュキーにこれを含めることが重要です。これは私たちが既に行っていることですが、Cookieは影響を与えません。これらはすべて自動的に処理されます。近々、お客様からご要望の多かったファイアウォールのサポートも追加される予定です。 アプリケーションの開発とデプロイが完了したので、 CloudWatchを使用してアプリケーションを監視していきます。CloudWatchの設定は、これまでの他のサービスと同様の方法で行います。 CloudWatchはまだAmplify Backendに組み込まれていませんが、Amplifyは究極的にはCDKなので、backend typesファイルを再度開いて、CDKを使用してCloudWatch RUMモニターを定義することができます。素晴らしいのは、参照できることです。
CloudWatch RUM app monitorをCDKで使用すると、強力な組み込み機能が提供されます。CloudWatch RUMを設定するには、Cognitoアイデンティティプール情報が必要ですが、これはAmplify認証リソースを参照することで簡単に取得できます。クライアント側では、 すべての環境で正しいCloudWatch RUMインスタンスを使用していることを確認したいと思います。アイデンティティプールをハードコーディングする代わりに、バックエンド情報を参照することができます。バックエンド設定からの出力により、ハードコーディングすることなくクライアントからバックエンドを参照でき、すべての環境で確実に動作します。
その結果、包括的な機能セットが得られます。CloudWatch RUMダッシュボードは、パフォーマンスメトリクス、エラー追跡、ユーザージャーニーを提供します。カスタムな計装を必要とせずに、ページロードやロード時間などの複数のメトリクスが自動的に取得されます。右側に表示されているエラーは、アプリに追加したカスタムエラー計装によるものです。 さらに詳しく見ると、時間帯に基づくロード時間を示す興味深いビューがあり、快適な体験と不快な体験の異なるしきい値が定義されています。幸いなことに、私のアプリは快適な範囲で動作しています。
これらの高レベルなメトリクスの他に、重要なメトリクスを確認することができます。 P75レベルでは、First Paint timing、最初のユーザー入力までの時間、読み込み中のレイアウトシフト(これはお客様にとってフラストレーションの原因となる可能性があります)を監視できます。アプリが常にグリーンゾーンにあることを確認できて嬉しく思います。 ユーザージャーニーについては、CloudWatch RUMはカスタムな計装なしで組み込みのトラッキングを提供します。ランディングページでのドロップオフはなく、最初のインタラクション後に4件のドロップオフ、2回目のインタラクション後に2件のドロップオフがあることがわかります。この自動トラッキングは、ページ遷移以外にもカスタマイズして含めることができます。
CloudWatch RUMはX-Rayと統合されているため、包括的なスタックトレースが得られます。 ユーザーインタラクションを見ると、ローカルマシンがlocalhostとして表示され、本番環境ではAmplify hostingとして表示されます。AppSyncとDynamoDBのバックエンドとのインタラクションがすべて1つのビューで確認できます。 AppSyncをより深く掘り下げると、X-Ray統合のおかげで、AppSyncコール内で何が起きているかを調べることができます。例えば、get car listingコールがどのようにさまざまなAppSync操作に分解されるかを確認でき、さらにその下にDynamoDB操作も表示されます。
本番環境のアプリケーションでは、CloudWatch Syntheticsを使用してCanaryをセットアップすることができます。今回のデモでは実装していませんが、APIチェックやハートビートモニタリングのための組み込みオプションが用意されています。Canaryの作成は、ポイント&クリックによる記録で行うことも、インラインエディタで直接作成することも、S3からインポートすることもできます。 CloudWatch RUMとCloudWatch Syntheticsの両方で、最近大きなアップデートがありました。CloudWatch RUMは監査目的ですべてのPutイベントを監査するようになり、CloudWatch SyntheticsはJavaScriptやNode.jsコミュニティで人気のツールであるPlaywrightをサポートするようになりました。
構築したアプリケーションの振り返りと結び
このトークで構築したものを振り返ってみましょう。私たちは複数のサービスを使用してAWSバックエンドを作成しました:フロントエンド用のAmplifyホスティング、認証用のCognito、APIレイヤーとしてのAppSync、そしてLambda、DynamoDB、生成AIの機能のためのBedrockなどのサポートサービスです。 ユーザーフローはシンプルです:ユーザーがブラウザウィンドウにアクセスすると、Amplifyホスティングが静的なSSRコンテンツ、あるいはその組み合わせを提供します。 ユーザーが認証されていない場合は、Authenticatorコンポーネントを使用してログインするよう促されます。 ユーザーが車を閲覧する際、APIコールはアクセス制御のためにAWS AppSyncを経由します。オークション機能については、AppSyncのイベントAPIを使用してオークションイベントのパブリッシュとサブスクライブを実現しました。
これらすべてを約55分で実現しました。素晴らしい聴衆の皆様、ありがとうございました。私とNikkiはXで見つけることができます。ここには記載し忘れましたが、私はBlueskyにもいます。質問の時間がありますので、改めて素晴らしい聴衆の皆様に感謝申し上げます。残りのre:Inventをお楽しみください。
※ こちらの記事は Amazon Bedrock を利用することで全て自動で作成しています。
※ 生成AI記事によるインターネット汚染の懸念を踏まえ、本記事ではセッション動画を情報量をほぼ変化させずに文字と画像に変換することで、できるだけオリジナルコンテンツそのものの価値を維持しつつ、多言語でのAccessibilityやGooglabilityを高められればと考えています。
Discussion