🐶

Amplify SNS Workshop をAWS CDKでやってみる①

2022/12/19に公開

はじめに

AWS Amplifyは、簡単にWebアプリケーションを構築できて非常に便利です。私も、いくつかの案件でAmplifyを使用していて、とても重宝しています。

Amplifyと一言に言っても、

  • Amplify CLI/Consoleでバックエンドを構築
  • Amplify Studioでフロントエンドの開発
  • ウェブアプリケーションのホスティング

など様々な機能があります。私が使用しているのは、最後のウェブアプリケーションのホスティングだけで、他の機能は使っていません。

Amplifyの記事を調べると、大体CLIに関する記事が多く、AmplifyといえばCLIでバックエンド構築というイメージですが、試しにつかってみたところ

  • CLIの裏側で作られているバックエンドの中身がよくわからない(ブラックボックス化しやすい)
  • 細かい部分で融通が利かない

等の不満があり、Amplify CLIを実際の案件に導入することはしていません。もともとインフラは、すべてコードで管理したいという要望もあり、AWS CDKなどで管理しています(CDKも、直接CloudFormationを編集するわけではないので、ブラックボックスといえなくもないですが、Amplify CLIよりは融通が利くうえ、TypeScriptで書けるので非常に便利です)。

そこで、今回は、AWS Amplifyの、 Twitter ライクなソーシャルメディアアプリケーションを構築するWorkshopをAWS CDKを使って構築してみます。

なお、構築にあたり、本家のAmplify SNS Workshopと、以下を変えています

  • フロントエンドをNext.jsで構築(Next.jsの方が好きなため)
  • GraphQLのスキーマを少し修正
  • フロントエンドのMaterialUIをv5に(今更v4やるのも・・)
  • バックエンド(CDK)と、フロントエンド(Next.js)のリポジトリを分離
  • 6.全文検索機能の追加以降はやらない
  • npmではなく、yarnを使用

また、開発に使用した環境、ツールは以下の通りです。

項目
OS Windows
Node.js のバージョン管理 Volta
Node.jsのバージョン 18.12.1
yarnのバージョン 1.22.19
IDE WebStorm

なお、実行にはCDKを使えるようにしておく必要があります。こちらの必要条件を読んで、AWS CLIと、AWS CDK Toolkitを用意しておいてください

MVPを作ろう!

本家のWorkshopでは、最初に以下のようなストーリーで始まります。とりあえず、今回の記事では、ここまで進めます。

Story

あなたの友人のユキは、ユーザーが最大140字程度の短いテキストを投稿して繋がるソーシャルメディアアプリ「Boyaki」を思いつきました。 とりあえずものを見せてくれ!と投資家に言われたユキは、友人のあなたに3日でMVP(Minimum Viable Product)を作るよう依頼します。 ユキのアイデアに可能性を見出したあなたはMVPの作成を引き受けました。 クイックにMVPを作るためAWS Amplifyを活用することにします。 さあ、投資家に見せるMVPを短期間で作成しましょう!

本セクションで実装するもの

  • ログイン機能

Bootstrap

作業ディレクトリの作成

任意のディレクトリに移動していただいた後、次のコマンドを実行し、本ワークショップの作業を行うディレクトリを作成します。

mkdir cdk-sns-workshop
cd cdk-sns-workshop

Creating a CDK project

新しい TypeScript CDK プロジェクトを作成するために cdk init を使います。

cdk init sample-app --language typescript

CDKは、TypeScript以外にもGo言語などでも使えるようですが、今回はTypeScriptでやります。なお、CDKのWorkshopも非常に勉強になるので、CDKを触るのが初めての人は、こちらもやっておいた方が良いです。

作成されたプロジェクトをIDEで開くと、こんな感じのフォルダ構成になっています。

最初に、自分の開発スタイルに合わせて、以下を修正します。このあたりは、人それぞれだと思うので、私がやりやすいようにやっているだけなので、もし、この記事を見て実際に作成される場合は、ご自身のやり方に修正してください。

①package.jsonにvoltaの情報を追加

package.jsonに以下の記載を追加

  ...,
  "dependencies": {
    "aws-cdk-lib": "2.52.0",
    "constructs": "^10.0.0"
  },
+  "volta": {
+    "node": "18.12.1",
+    "yarn": "1.22.19"
  }
}

②yarnに変更

yarn installを実行し、

yarn install

package-lock.jsonを削除

③preitterを導入

yarn add -D prettier

プロジェクトルートディレクトリに、.prettierrcというファイルを作成し、以下のように記載

{
  "semi": false,
  "trailingComma": "all",
  "singleQuote": false,
  "printWidth": 100,
  "tabWidth": 2
}

WebStormを使用している場合は、保存時に、自動的に実行されるように設定しておきます。

④Gitにpush

最初にGitのリポジトリに登録しておきます。なお、この記事のリポジトリは、こちらです。

認証機能

最初に、アプリケーションに認証機能を実装します。本家のWorkshopと同じようにCognitoを使用します。

認証機能の追加

最初に以下のコマンドでパッケージを追加します。

yarn add @aws-cdk/aws-cognito-identitypool-alpha

cdk-sns-workshop-stack.tsを以下のように修正します。

import {
  IdentityPool,
  UserPoolAuthenticationProvider,
} from "@aws-cdk/aws-cognito-identitypool-alpha"
import { CfnOutput, Stack, StackProps } from "aws-cdk-lib"
import {
  AccountRecovery,
  UserPool,
  UserPoolClient,
  VerificationEmailStyle,
} from "aws-cdk-lib/aws-cognito"
import { Construct } from "constructs"

export class CdkSnsWorkshopStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props)

    const userPool = new UserPool(this, "UserPool", {
      selfSignUpEnabled: true,
      accountRecovery: AccountRecovery.PHONE_AND_EMAIL,
      userVerification: {
        emailStyle: VerificationEmailStyle.CODE,
      },
      autoVerify: {
        email: true,
      },
      keepOriginal: { email: true },
      standardAttributes: {
        email: {
          required: true,
          mutable: true,
        },
      },
    })

    const userPoolClient = new UserPoolClient(this, "UserPoolClient", {
      userPool,
    })

    const identityPool = new IdentityPool(this, "IdentityPool", {
      allowUnauthenticatedIdentities: true,
      authenticationProviders: {
        userPools: [
          new UserPoolAuthenticationProvider({
            userPool: userPool,
            userPoolClient: userPoolClient,
          }),
        ],
      },
    })

    new CfnOutput(this, "UserPoolId", { value: userPool.userPoolId })
    new CfnOutput(this, "UserPoolClientId", { value: userPoolClient.userPoolClientId })
    new CfnOutput(this, "IdentityPoolId", {
      value: identityPool.identityPoolId,
    })
  }
}

ここまで出来たら、とりあえず、デプロイしてみます。

CDKをデプロイする場合、「 Bootstrap スタック」をお使いのAWSにインストールしておく必要があります。すでにCDKを使ったことがある方は以下のコマンドは不要です。

cdk bootstrap

アクセスが拒否される場合は、AWS CLIのクレデンシャルを確認してください。

次にデプロイします。

cdk deploy

なお、事前に、cdk synthコマンドで、CloudFormationの定義を出力して確認することも可能です。

デプロイにセキュリティに関するリスクが伴うことを警告されますが、内容を確認して、yと回答します。

デプロイが完了すると、AWSのコンソールで、CloudFormationのスタックと、Cognitoのユーザープールなどが構築できていることが確認できます。

認証機能のフロントエンドへの実装

次にフロントエンドをNext.jsで作成します。本家のWorkshopとは違い、フロントエンド(Next.js)と、バックエンド(AWS CDK)は別のディレクトリ(リポジトリで管理します)

任意のディレクトリで以下のコマンドを実行

yarn create next-app --typescript

色々聞かれるので以下のように回答します

? What is your project named? » cdk-sns-workshop-next
? Would you like to use ESLint with this project? » No

するとNext.jsのプロジェクトが構築されます。

CDKのリポジトリと同じように、最初に、volta、preitterの導入、Gitへの登録をやっておきます。なお、リポジトリはこちらです。

必要なパッケージを追加

認証周りは、AmplifyのUIを利用します。以下のコマンドで必要なパッケージを追加します。

 yarn add aws-amplify @aws-amplify/ui-react

最初に、ルートディレクトリ直下に、aws-config.tsというファイルを作成し、以下のように記載します。

const AWSConfiguration = {
  Auth: {
    region: process.env.NEXT_PUBLIC_PROJECT_REGION,
    userPoolId: process.env.NEXT_PUBLIC_USER_POOLS_ID,
    userPoolWebClientId: process.env.NEXT_PUBLIC_USER_POOL_CLIENT_ID,
    identityPoolId: process.env.NEXT_PUBLIC_IDENTITY_POOL_ID,
  },
}

export default AWSConfiguration

なお、userPoolId, userPoolWebClientId, identityPoolIdは、CDKで作成したCloudFormationのスタックの出力から確認できます。ここでは、環境変数として与えるようにしています。

認証機能の実装

page/_app.tsxを以下のように修正します。

import "../styles/globals.css"
import { Amplify } from "aws-amplify"
import type { AppProps } from "next/app"

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

Amplify.configure(config)

export default function App({ Component, pageProps }: AppProps) {
  return (
    <Authenticator.Provider>
      <Component {...pageProps} />
    </Authenticator.Provider>
  )
}

次に、page/index.tsxを以下のように修正します。

import { Authenticator, translations } from "@aws-amplify/ui-react"
import "@aws-amplify/ui-react/styles.css"
import { I18n } from "aws-amplify"
import { NextPage } from "next"

I18n.putVocabularies(translations)
I18n.setLanguage("ja")

const Page: NextPage = () => {
  return (
    <Authenticator signUpAttributes={["email"]}>
      {({ signOut, user }) => (
        <main>
          <h1>Hello {user?.username || "unknown"}</h1>
          <button onClick={signOut}>Sign out</button>
        </main>
      )}
    </Authenticator>
  )
}

export default Page

ローカルで実行してみる

yarn devでローカルで実行し、http://localhost:3000にブラウザでアクセスすると、以下のような画面が表示されます。

アカウントを作るから、新規にアカウントを作成してみると、

以下のような表示になり、前のページで指定したメールアドレスに、コードが届きますので、そのコードを入力してください。

すると、アカウントが作成されます。AWSのマネジメントコンソールでCognitoにユーザーが追加されていることが確認できます。

とりあえず、今回はここまで、次回は、AppSyncを使用して、Post機能の作成とそれをフロントエンドで表示するまでを実施します。

参考文献

Discussion