Amazon Web Services ブログ
AWS Amplify、TanStack、AppSync、MongoDB Atlas を使用したオフラインキャッシング
このブログでは、AWS Amplify、AWS AppSync、MongoDB Atlas を使用して、オフラインファーストのアプリケーションと楽観的な UI を作成する方法をご紹介します。開発者は、インターネット接続を必要としないオフラインファーストアプリケーションを設計します。楽観的な UI は、サーバーからのレスポンスに依存することなく、予想されるデータの変更で UI を更新することで、オフラインファーストのアプローチをさらに発展させます。このアプローチは通常、ローカルキャッシュの仕組みを活用します。
オフラインファーストと楽観的 UI を組み合わせたアプリケーションは、ユーザーに多くの利点をもたらします。これには、ローディング画面を実装する必要性の低減、データアクセスの高速化によるパフォーマンスの向上、アプリケーションがオフラインの状態におけるデータの信頼性、コスト効率の向上が含まれます。オフライン機能を手動で実装するには相当な労力が必要ですが、このプロセスを簡素化するツールを使用することができます。
リクエストのラウンドトリップが完了する前に MongoDB Atlas の CRUD 操作の結果を UI に即座に表示し、ユーザーエクスペリエンスを向上させる、サンプルの Todo アプリケーションを提供しています。つまり、楽観的 UI を実装することで、ローディング状態やエラー状態の表示を容易にし、API 呼び出しが失敗した場合に開発者が UI 上の変更をロールバックできるようにしています。この実装では、TanStack Query を活用して、AWS Amplify と共に楽観的な UI の更新を処理します。図 1 は、UI とバックエンド間の連携を示しています。
TanStack Query は、TypeScript/JavaScript、React、Solid、Vue、Svelte、Angular 向けの非同期状態管理ライブラリです。Web アプリケーションにおけるサーバー状態のフェッチ、キャッシング、同期、更新を簡素化します。TanStack Query のキャッシングメカニズムを活用することで、ネットワーク接続がなくてもデータの可用性を確保できます。AWS Amplify が開発プロセスを効率化し、AWS AppSync が信頼性の高い GraphQL API レイヤーを提供し、MongoDB Atlas がスケーラブルなデータベースソリューションを提供します。この統合により、フルスタックアプリケーションアーキテクチャ内で TanStack Query のオフラインキャッシュを効果的に活用する方法が示されています。
図 1. インタラクション図
このサンプルアプリケーションは、一般的な ToDo 機能を実装しており、その具体的なアーキテクチャは 図 2 に示されています。このスタックの構成は以下の通りです。
- データベースサービスには MongoDB Atlas を使用します。
- フルスタックアプリケーションフレームワークには AWS Amplify を使用します。
- GraphQL API 管理には AWS AppSync を使用します。
- サーバーレスコンピューティングには AWS Lambda Resolver を使用します。
- ユーザー管理と認証には Amazon Cognito を使用します。
図 2. アーキテクチャ
アプリケーションのデプロイ
アプリを AWS アカウントにデプロイするには、以下の手順に従ってください。デプロイが完了したら、ユーザーを作成し、認証を行い、Todo エントリを作成できます (図 8 を参照)。
MongoDB Atlas クラスターのセットアップ
- こちらのリンク先で、MongoDB Atlas クラスター、データベース、ユーザー、ネットワークアクセスをセットアップします
- ユーザーをセットアップします
GitHub リポジトリのクローン
- 以下のコマンドでサンプルアプリケーションをクローンします
git clone https://github.com/mongodb-partners/amplify-mongodb-tanstack-offline
AWS CLI 認証情報のセットアップ (ローカルでアプリケーションをデバッグする場合のオプション)
- サンドボックス環境を使用してアプリケーションをローカルでテストする場合は、一時的な AWS 認証情報をローカルに設定できます。
export AWS_ACCESS_KEY_ID=
export AWS_SECRET_ACCESS_KEY=
export AWS_SESSION_TOKEN=
AWS Amplify に Todo アプリケーションをデプロイ
- AWS Amplify コンソールを開き、GitHub オプションを選択
図 3. GitHub オプションの選択
2. GitHub リポジトリの設定
図 4. リポジトリのアクセス許可を設定
3. GitHub リポジトリを選択し、Next をクリック
図 5. リポジトリとブランチの選択
4. その他のオプションはすべてデフォルトのままにして、デプロイ
図 6. アプリケーションのデプロイ
環境変数の設定
デプロイが成功したら、環境変数を設定
図 7. 環境変数の設定
アプリケーションの起動とテスト
提供された URL からアプリケーションを開き、テストを実施します。
図 8. Todo エントリのサンプル
MongoDB Atlas の出力
図 9. MongoDB 内のデータ
アプリケーションの確認
アプリケーションがデプロイされたので、内部で何が起きているのか、何が設定されたのかについて説明しましょう。 Amplify の Git ベースのワークフローを活用して、継続的デプロイメントを備えたフルスタックのサーバーレス Web アプリケーションをホストしました。Amplify は、Next.js や Nuxt のようなサーバーサイドレンダリング (SSR) フレームワーク、React や Angular のようなシングルページアプリケーション (SPA) フレームワーク、Gatsby や Hugo のような静的サイトジェネレーター (SSG) など、さまざまなフレームワークをサポートしています。今回は、SPA の React ベースのアプリケーションをデプロイしました。フィーチャーブランチ、カスタムドメイン、プルリクエストのプレビュー、エンドツーエンドテスト、リダイレクト/リライトを含めることができます。Amplify Hosting は Git ベースのワークフローを提供し、デプロイ全体が完了した後にのみ更新が適用されるアトミックデプロイメントを実現します。
アプリケーションのデプロイには AWS Amplify Gen 2 を使用しました。これは TypeScript を使用したフルスタックアプリケーションの開発とデプロイを簡素化するために設計されたツールです。クラウドリソースの管理には AWS Cloud Development Kit (CDK) を活用し、スケーラビリティと使いやすさを確保しています。
最後に、アプリケーションの更新の同時実行性について理解することが重要です。私たちは、シンプルな楽観的先着順の競合解決メカニズムを実装しました。MongoDB Atlas クラスターは、受信した順序で更新を永続化します。更新が競合した場合、最後に到着した更新が以前の更新を上書きします。このメカニズムは、更新の競合が少ないアプリケーションでは有効に機能します。本番環境のニーズに合わせて、より高度なアプローチの必要性を検討することが重要です。TanStack は、さまざまな接続シナリオを処理するためのより複雑なメカニズムを提供します。デフォルトでは、TanStack Query は「オンライン」ネットワークモードを提供し、ネットワーク接続がない限りクエリとミューテーションは実行されません。クエリの実行中にオフラインになった場合、TanStack Query はリトライメカニズムも一時停止します。一時停止されたクエリは、ネットワーク接続が回復すると実行を再開します。UI を新しい値や変更された値で楽観的に更新するために、想定されるレスポンスでローカルキャッシュを更新することもできます。このアプローチは、TanStack の「オンライン」ネットワークモードと相性が良く、アプリケーションにネットワーク接続がない場合、ミューテーションは実行されずにキューに追加されますが、UI の更新にはローカルキャッシュを使用できます。下は、サンプルアプリケーションが期待されるミューテーション結果でUIを楽観的に更新する重要な例です。
const createMutation = useMutation({
mutationFn: async (input: { content: string }) => {
// Use the Amplify client to make the request to AppSync
const { data } = await amplifyClient.mutations.addTodo(input);
return data ;
},
// When mutate is called:
onMutate: async (newTodo) => {
// Cancel any outgoing refetches
// so they don't overwrite our optimistic update
await tanstackClient.cancelQueries({ queryKey: ["listTodo"] });
// Snapshot the previous value
const previousTodoList = tanstackClient.getQueryData(["listTodo"]);
// Optimistically update to the new value
if (previousTodoList) {
tanstackClient.setQueryData(["listTodo"], (old: Todo[]) => [
...old,
newTodo,
]);
}
// Return a context object with the snapshotted value
return { previousTodoList };
},
// If the mutation fails,
// use the context returned from onMutate to rollback
onError: (err, newTodo, context) => {
console.error("Error saving record:", err, newTodo);
if (context?.previousTodoList) {
tanstackClient.setQueryData(["listTodo"], context.previousTodoList);
}
},
// Always refetch after error or success:
onSettled: () => {
tanstackClient.invalidateQueries({ queryKey: ["listTodo"] });
},
onSuccess: () => {
tanstackClient.invalidateQueries({ queryKey: ["listTodo"] });
},
});
追加の競合解決戦略を実装する プルリクエストを歓迎します。
- AWS MarketPlace で MongoDB Atlas を試してみましょう。
- AWS Amplify、Amplify Gen2、AppSync について理解を深めましょう。
- アプリケーションのデプロイに関する詳細な手順については、ドキュメントのデプロイの手順を参照してください。
- 改善点をプルリクエストとして提出してください
本記事は、2025 年 6 月 19 日に公開された Offline caching with AWS Amplify, TanStack, AppSync and MongoDB Atlas を翻訳したものです。翻訳は Solutions Architect の吉村が担当しました。