💡

【AWS Amplify Gen 2】テンプレートを活用してフルスタックアプリをサクッとデプロイしてみた

に公開

はじめに

フロントエンドエンジニアがバックエンドを含めたフルスタックな開発を迅速に行うためのツールとして、AWS Amplifyが広く利用されている。2024年に登場したAWS Amplify Gen 2は、これまでのGen 1で課題だった設定の複雑さが解消されており、かなり使いやすくなっている。

本記事では、公式ドキュメントのクイックスタートをベースに、Next.js(App Router)を用いたWebアプリケーションをAmplify Gen 2でデプロイし、さらにローカル環境でデータ削除機能や認証機能を追加するまでの流れを解説する。

前提条件

  • AWSおよびGitHubのアカウントは既に作成済みとする
  • GitおよびNode.jsは既にインストール済みとする。

公式ドキュメント

https://docs.amplify.aws/nextjs/start/quickstart/nextjs-app-router-client-components/

AWS Amplify Gen 2とは

https://aws.amazon.com/jp/amplify/

  • フロントエンドエンジニアが、サーバーレスのバックエンド(認証、DB、API、ホスティング、配信)を自動構築・管理できる包括的なクラウドサービス
  • CLIツールやライブラリを用い、数行のコードでAWSサービスと統合できるため、フルスタック開発の迅速化に最適
  • Gen 1はAmplify CLIの設定が必要で少々面倒だったが、Gen 2では不要になった

Gen 1からの変更点

比較項目 Gen 1 Gen 2
定義手法 CLIによる対話型コマンド TypeScriptコードによる直接定義
基盤技術 AWS CloudFormation AWS CDK (Cloud Development Kit)
設定ファイル aws-exports.js amplify_outputs.json
デプロイ方法 amplify pushコマンド等 git pushによる自動デプロイ
データモデル定義 GraphQL Schema (SDL) TypeScriptベースのスキーマ定義

構成イメージ

AWS Amplify Gen 2にデプロイするまでの手順

GitHubリポジトリの作成

公式ドキュメントにあるCreate repository from templateボタンを選択し、リポジトリを作成する。今回はお試しなので初期設定のままCreate repositoryを選択する。

Amplifyへのデプロイ

公式ドキュメントにあるDeploy to AWSボタンを選択すると、下記のようなページが表示される。
ここではGitHubを選択して次へをクリックする。

OAuth認証を要求されるので、Authorize AWS Amplifyをクリックする。

下記の画面では、インストールと認可の対象となるリポジトリを選択する。
今回はOnly select repositoriesを選択し、先程作成したリポジトリを選択する。

リポジトリとブランチを選択する画面に遷移するので、それぞれ適切なものを選択する。

アプリケーションの設定画面に遷移する。
ビルドの設定等は自動で設定されるので、このままで問題なければ次へを選択する。

最終確認の画面に遷移するので、問題なければ保存してデプロイを選択する。

5分程度待つとデプロイが完了して下記のような画面が表示される。

デプロイされたURLにアクセスを選択し、下記のような画面が表示されたら成功である。

テンプレートをローカル環境で改造する

git clone

この段階だとまだテンプレートをそのままデプロイしただけである。
ここから開発者の好きなようにWebアプリを改造していきたいのであれば、
下記のコマンドで一旦ローカル環境にクローンしておこう。

git clone https://github.com/<github-user>/amplify-next-template.git
cd amplify-next-template && npm install

amplify_outputs.jsonの配置

デプロイのページからamplify_outputs.jsonをダウンロードする。

そして、下記のようにプロジェクトのルートディレクトリに配置する。このファイルには、
フロントエンドがバックエンドに接続するためのAPIキーやエンドポイント情報が含まれている。

データ削除機能の追加

ここではapp/page.tsxDeleteTodo関数を追加し、データの削除ができるようにする。
変更箇所は緑色のハイライトがかかっている部分のみでOK。

app/page.tsx
"use client";

import { useState, useEffect } from "react";
import { generateClient } from "aws-amplify/data";
import type { Schema } from "@/amplify/data/resource";
import "@/app/app.css";
import { Amplify } from "aws-amplify";
import outputs from "@/amplify_outputs.json";
import "@aws-amplify/ui-react/styles.css";

Amplify.configure(outputs);

const client = generateClient<Schema>();

export default function App() {
  const [todos, setTodos] = useState<Array<Schema["Todo"]["type"]>>([]);

  function listTodos() {
    client.models.Todo.observeQuery().subscribe({
      next: (data) => setTodos([...data.items]),
    });
  }

  useEffect(() => {
    listTodos();
  }, []);

  function createTodo() {
    client.models.Todo.create({
      content: window.prompt("Todo content"),
    });
  }

+  // TodoのIDを指定して削除する関数
+  function deleteTodo(id: string) {
+    client.models.Todo.delete({ id });
+  }

  return (
    <main>
      <h1>My todos</h1>
      <button onClick={createTodo}>+ new</button>
      <ul>
        {todos.map((todo) => (
          <li
+            // Todoをクリックすると削除されるようにする
+            onClick={() => deleteTodo(todo.id)}
            key={todo.id}>{todo.content}
           </li>
        ))}
      </ul>
      <div>
        🥳 App successfully hosted. Try creating a new todo.
        <br />
        <a href="https://docs.amplify.aws/nextjs/start/quickstart/nextjs-app-router-client-components/">
          Review next steps of this tutorial.
        </a>
      </div>
    </main>
  );
}

ログイン・ログアウト機能の追加

@aws-amplify/ui-reactライブラリのAuthenticatorコンポーネントを利用することで、
かなりお手軽にログイン・ログアウト機能を実装することができる。
そのため、まずはapp/AuthenticatorWrapper.tsxを追加する。

app/AuthenticatorWrapper.tsx
"use client"

import { Authenticator } from "@aws-amplify/ui-react";

export default function AuthenticatorWrapper({
  children,
}: {
  children: React.ReactNode;
}) {
  return <Authenticator>{children}</Authenticator>;
}

次に、app/layout.tsxにてAuthenticatorWrapperコンポーネントを利用する。
これでログイン機能の実装は完了である。

app/layout.tsx
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "@/app/app.css";

+ import AuthenticatorWrapper from "./AuthenticatorWrapper";
+ import "@aws-amplify/ui-react/styles.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
+    <html lang="ja">
+      <body className={inter.className}>
+        <AuthenticatorWrapper>
+          {children}
+        </AuthenticatorWrapper>
+      </body>
+    </html>
  );
}

ログアウトボタンを実装するために、再度app/page.tsxを編集する。

app/page.tsx
"use client";

import { useState, useEffect } from "react";
import { generateClient } from "aws-amplify/data";
import type { Schema } from "@/amplify/data/resource";
+ import { useAuthenticator } from "@aws-amplify/ui-react";
import "@/app/app.css";
import { Amplify } from "aws-amplify";
import outputs from "@/amplify_outputs.json";
import "@aws-amplify/ui-react/styles.css";

Amplify.configure(outputs);

const client = generateClient<Schema>();

export default function App() {
  const [todos, setTodos] = useState<Array<Schema["Todo"]["type"]>>([]);
+  const { signOut } = useAuthenticator();

  function listTodos() {
    client.models.Todo.observeQuery().subscribe({
      next: (data) => setTodos([...data.items]),
    });
  }

  useEffect(() => {
    listTodos();
  }, []);

  function createTodo() {
    client.models.Todo.create({
      content: window.prompt("Todo content"),
    });
  }

+  // TodoのIDを指定して削除する関数
+  function deleteTodo(id: string) {
+    client.models.Todo.delete({ id });
+  }

  return (
    <main>
      <h1>My todos</h1>
      <button onClick={createTodo}>+ new</button>
      <ul>
        {todos.map((todo) => (
          <li
+            // Todoをクリックすると削除されるようにする
+            onClick={() => deleteTodo(todo.id)}
            key={todo.id}>{todo.content}
           </li>
        ))}
      </ul>
      <div>
        🥳 App successfully hosted. Try creating a new todo.
        <br />
        <a href="https://docs.amplify.aws/nextjs/start/quickstart/nextjs-app-router-client-components/">
          Review next steps of this tutorial.
        </a>
      </div>
+      <button onClick={signOut}>Sign out</button>
    </main>
  );
}

変更をデプロイ済みのアプリに反映させる

GitHubにPushすると自動的にAmplifyの方にもデプロイされる。
そのため、下記のコマンドでGitHubへのPushをしておこう。

git add .
git commit -m "データ削除機能および認証機能の追加"
git push

デプロイが完了したら再度デプロイされたURLにアクセスし、
ローカルで開発した機能が正しく反映されているかを確認しておこう。

使わないWebアプリは削除しておく

デプロイしたWebアプリを放置しておくと、botやクローラーにアクセスされて微妙に課金が発生する可能性もあるため、実験目的でデプロイしたアプリについては削除しておくことをおすすめする。アプリの削除は、アプリケーションの設定: 全般設定の画面から選択できる。

おわりに

今回は、AWS Amplify Gen 2を使用して、Next.jsアプリケーションの構築から認証機能の実装、そしてGitHub連携による自動デプロイまでの流れを確認した。
実際に触ってみての所感としては、まず初回のデプロイ自体が非常に簡単になっていることと、ローカル環境で編集してからgit pushをすると自動的にデプロイまでしてくれるところがとてもエラいなと思った。それでいてAWSの強固な基盤ともシームレスに連携できるため、大規模なプロジェクトでも活用しやすいサービスである。
今回実装した機能は基礎的なものではあるが、これだけでもAmplify Gen 2を活用することで、インフラの管理に頭を悩ませることなく、プロダクトの機能開発に集中できる環境が整うことが分かるだろう。

Discussion