【NextJS】Cognito with Amplify(Gen2)+CRUD(DynamoDB)

1. 概要

こちらのFlutterで実施した内容をNextJSでも行ってみます。

今回はAWS Amplify(Gen2)を使い、認証(Cognito)を行うのとTodoアプリを実装する内容となります。

対象としては開発を1年程やってて自分で最初から開発してみたい方になります。そのため細かい用語などの説明はしません。

「App router」で作成します。

2. 前提条件

2-1. こちらを参考

  • Node.js v14.x or later
  • npm v6.14.4 or later
  • git v2.14.1 or later
  • AWS Account

3. レポジトリの作成

3-1. こちらのテンプレートから作成

※GitHubにログインしておく

4. Amplifyへデプロイ

4-1. こちらのURLから

5. アプリへアクセス

5-1. 上記デプロイされたドメインへアクセス

  • https://main.12345678901234.amplifyapp.com/

6. ローカル環境のセットアップ

6-1-1. 「amplify_output.jsonをダウンロード

  • デプロイ画面の「デプロイされたバックエンドリソース」タブをクリックしてダウンロード

6-1-2. 自分PCにRepositoryをクーロン

git clone https://github.com/myAccount/amplify-next-template.git

6-1-3. ライブラリのインストール

cd amplify-next-template && npm install

6-1-4. ルートディレクトリに「amplify_outputs.json」をコピー

6-1-5. ディレクトリ構成

.
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── amplify
│   ├── auth
│   │   └── resource.ts
│   ├── backend.ts
│   ├── data
│   │   └── resource.ts
│   ├── package.json
│   └── tsconfig.json
├── amplify.yml
├── amplify_outputs.json
├── app
│   ├── app.css
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx
│   ├── page.module.css
│   └── page.tsx
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
└── tsconfig.json

4 directories, 22 files
  • 主要なファイル

7. 必要なライブラリをインストール

7-1-1. インストール

npm add @aws-amplify/ui-react

8. ローカルにAWS credentialsをセットアップ

8-1-1. こちらを参考

9. Amplifyのcloud sandboxを立ち上げ

npx ampx sandbox

10. ソースコード

10-1-1. amplify/data/resource.ts

import { type ClientSchema, a, defineData } from "@aws-amplify/backend";

/*== STEP 1 ===============================================================
The section below creates a Todo database table with a "content" field. Try
adding a new "isDone" field as a boolean. The authorization rule below
specifies that any user authenticated via an API key can "create", "read",
"update", and "delete" any "Todo" records.
=========================================================================*/
const schema = a.schema({
  Todo: a
    .model({
      content: a.string(),
      isDone: a.boolean(),
    })
    .authorization((allow) => [allow.owner()]),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "userPool",
    apiKeyAuthorizationMode: {
      expiresInDays: 30,
    },
  },
});

/*== STEP 2 ===============================================================
Go to your frontend source code. From your client-side code, generate a
Data client to make CRUDL requests to your table. (THIS SNIPPET WILL ONLY
WORK IN THE FRONTEND CODE FILE.)

Using JavaScript or Next.js React Server Components, Middleware, Server 
Actions or Pages Router? Review how to generate Data clients for those use
cases: https://docs.amplify.aws/gen2/build-a-backend/data/connect-to-API/
=========================================================================*/

/*
"use client"
import { generateClient } from "aws-amplify/data";
import type { Schema } from "@/amplify/data/resource";

const client = generateClient<Schema>() // use this Data client for CRUDL requests
*/

/*== STEP 3 ===============================================================
Fetch records from the database and use them in your frontend component.
(THIS SNIPPET WILL ONLY WORK IN THE FRONTEND CODE FILE.)
=========================================================================*/

/* For example, in a React component, you can use this snippet in your
  function's RETURN statement */
// const { data: todos } = await client.models.Todo.list()

// return <ul>{todos.map(todo => <li key={todo.id}>{todo.content}</li>)}</ul>

10-1-2. 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";
import { Authenticator } from "@aws-amplify/ui-react";
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"),
      isDone: false,
    });
  }

  function deleteTodo(id: string) {
    client.models.Todo.delete({ id });
  }

  function updateTodo(todo: Schema["Todo"]["type"]) {
    client.models.Todo.update({ id: todo.id, isDone: !todo.isDone });
  }

  return (
    <Authenticator>
      {({ signOut, user }) => (
        <main>
          <h1>{user?.signInDetails?.loginId}'s todos</h1>
          <h1>My todos</h1>
          <button onClick={createTodo}>+ new</button>
          <ul>
            {todos.map((todo) => (
              <li key={todo.id}>
                <div
                  style={{
                    display: "flex",
                    flexDirection: "row",
                    justifyContent: "space-between",
                  }}
                >
                  <span
                    onClick={() => deleteTodo(todo.id)}
                    style={{
                      width: "100%",
                      alignContent: "center",
                      textAlign: "left",
                    }}
                  >
                    {todo.content}
                  </span>
                  <span
                    style={{
                      width: "100%",
                      alignContent: "center",
                      textAlign: "right",
                    }}
                  >
                    <input
                      type="checkbox"
                      checked={todo.isDone!}
                      onChange={() => updateTodo(todo)}
                    />
                  </span>
                </div>
              </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>
      )}
    </Authenticator>
  );
}

機能

  • 認証
    • メールアドレス
    • パスワード
  • データ操作(Todo)
    • Create
    • Read
    • Update
    • Delete

11. サーバーを起動

npm run dev

12. ブラウザで確認(ローカル)

  • http://localhost:3000
    • 画面キャッチャーは下記の14を参照

13. ローカルからAmplifyへデプロイ

git add .
git commit -am "added isDone"
git push
  • CI/CDビルドがトリガーされる
    • デプロイ後、数分後にブラウザで確認

14. ブラウザで確認(Amplifyのデプロイドメイン)

  • https://main.12345678901234.amplifyapp.com/

15. 備考

今回はAWS Amplify(Gen2)を使い、認証(Cognito)を行うのとTodoアプリを実装する内容についてでした。

16. 参考

投稿者プロフィール

Sondon
開発好きなシステムエンジニアです。
卓球にハマってます。

関連記事

  1. 【NextJS】SassとTypescriptでレイアウトを構成

  2. 【NextJS】TextField

  3. 【Next.js】ローカル環境をSSL化してみる

  4. 【NextJS】ChatApp with Realtime updat…

  5. 【NextJS】Canvasを使い、図形を描画

  6. 【NextJS】Server Actions with MySQL

最近の記事

  1. raspberrypi

制作実績一覧

  1. Checkeys