【SAM + Cognito + Amplify ライブラリでログイン機能を実装した React アプリを作成】Part2 - React アプリから API 実行


みなさん、こんにちは。イノベーションLABのハヤシです。

以下の構成の Web アプリをさくっと作る手順をご紹介します。
 バックエンド:Node.js の REST API(Amazon API Gateway / AWS Lambda)
 フロントエンド:TypeScript の React

今回は全 3 回のうちの 2 回目、フロントエンド実装編です。
必要な部分だけでも、ぜひ参考にしてみてください。

1回目はこちら↓
blog.css-net.co.jp


1. 前提条件

1-1. 想定読者

「さくっとログイン機能を実装した Web アプリが作りたい」
「せっかくなら SPA + REST API でやりたい」
「AWS SAM や Amplify ライブラリを使ってみたい」
といった方々を想定しています。


必要最低限の方法のみ解説しているので、ほぼサンプルコードのままです。
その後のカスタマイズには、 Node.js や TypeScript / React の知識が必要になります。


とはいえ、この記事は知識があることを前提としていませんので、手順通りに実施していく分にはそれらの知識は不要です。
雰囲気をつかむために、まずはチャレンジしてみるのもおすすめです!

1-2. 前提条件

OS - Windows 10 Pro (Home でも問題ありません)
VSCode - 1.69.1
Git - 2.37.1.windows.1
AWS CLI - 2.7.14
SAM CLI - 1.53.0
Node.js - 16.16.0


aws configure で認証設定がすんでいること
以下コマンドで、「Account」が自分が操作可能な Account ID になっていることを確認する

aws sts get-caller-identity

# Profile を指定している場合は今後のコマンドも全て Profile を指定してください
# aws sts get-caller-identity --profile <Profile名>


この後の手順は特に指示がない限り、エディタは VSCode でターミナルは Git Bash での操作となります

環境構築手順はこちらで紹介しています
blog.css-net.co.jp

1-3. この手順でインストールするもの

React - 18.2.0
TypeScript - 4.7.4
aws-amplify - 4.3.27
@aws-amplify/ui-react - 3.0.4

2. フロントエンド SPA

2-1. React アプリ作成

前回作成した作業用ディレクトリ(「C:\work\tutorial-app」)をVSCode で開きます。
この状態からスタートです。
VSCode のターミナルで作業します。


以下のコマンドで、 TypeScript で React アプリを作成します。

npx create-react-app tutorial-app-front --template typescript


Amplify に必要なライブラリをインストールします。

cd tutorial-app-front
npm install aws-amplify @aws-amplify/ui-react

※React 18 との依存関係でエラーになる場合は以下のコマンドで強制的にインストールしてください

npm install aws-amplify @aws-amplify/ui-react --legacy-peer-deps

参考
React 18 peer dependency errors from radix dependencies · Issue #2089 · aws-amplify/amplify-ui · GitHub


tutorial-app-front ディレクトリで以下コマンドを実行して、ブラウザ(http://localhost:3000/)でアプリが立ち上がることを確認します。

npm start


2-2. コンポーネント分割

このあとログイン処理を実装するため、ページを分割しておきます。
VSCode のターミナルで作業します。
フロントエンド用ディレクトリ(C:\work\tutorial-app\tutorial-app-front)にいる前提で進めていきます。


src/pages ディレクトリを新規作成し、 Home.tsx ファイルを以下の内容で追加します。
src/pages/Home.tsx

import React from 'react';

const Home = () => {
  return (
    <div>
      ようこそ!
    </div>
  );
}

export default Home;


App.tsx ファイルを、今作成した Home コンポーネントを呼び出すように書き換えておきます。
src/App.tsx

import React from 'react';
import './App.css';
import Home from './pages/Home';

function App() {
  return (
    <div className="App">
      <Home />
    </div>
  );
}

export default App;


ブラウザでの表示がこのようになっていれば OK です。


確認ができたら Ctrl + C で、一度アプリを停止しておきます。

2-3. リポジトリに登録

ここまでの状態で Push しておきましょう。
VSCode のターミナルで作業します。
フロントエンド用ディレクトリ(C:\work\tutorial-app\tutorial-app-front)にいる前提で進めていきます。


以下のコマンドで、バックエンドの時と同様にローカルリポジトリとリモートリポジトリを紐づけます

git remote add origin https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/tutorial-app-front

※「https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/tutorial-app-front」の部分は、前回記事でリポジトリ作成時に確認した front 用のリポジトリの HTTPS パスを指定してください


以下のコマンドで、ブランチ名の変更とリモートリポジトリへの Push をします。

git branch -m main
git add .
git commit -m "first commit"
git push origin main


マネジメントコンソールで作業します。
ファイルがアップされていることを確認します。
◆CodeCommit -> ソース -> リポジトリ -> tutorial-app-front

2-4. Amplify ライブラリの設定

src/aws-exports.js ファイルを追加して、Amplify ライブラリで AWS リソースを使う設定を書き込みます。
VSCode のターミナルで作業します。
フロントエンド用ディレクトリ(C:\work\tutorial-app\tutorial-app-front)にいる前提で進めていきます。

src/aws-exports.js

const config = {
  API: {
      endpoints: [
          {
              name: "MainApi",
              endpoint: process.env.REACT_APP_AWS_API_ENDPOINT_MAIN,
          },
      ]
  }
};

export default config;

このファイルでは、環境変数から API のエンドポイントを取得するようになっています。
環境変数の設定ファイルを追加しましょう。


まずは API のエンドポイントを確認しておきます。

◆---------- APIのエンドポイント確認方法(クリックで開く) ----------◆

マネジメントコンソールで作業します。
1. API Gateway 画面から確認
◆API Gateway -> API -> tutorial-app-api
ステージ -> dev -> 「URL の呼び出し:」に記載されています。


2. CloudFormation 画面から確認
◆CloudFormation -> スタック -> tutorial-app-back-stack
出力 -> 「WebEndpoint」の値です。

◆---------- APIのエンドポイント確認方法 ここまで ----------◆


.env ファイルを追加して、以下の内容で保存します。(確認した API のエンドポイントを記載してください)
.env

REACT_APP_AWS_API_ENDPOINT_MAIN="https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev"


環境変数ファイルは .gitignore へ記載してリポジトリ管理から外しておきます。

echo .env >> .gitignore

かわりにサンプルファイルを追加しておきます。
.env_sample ファイルを作成し、以下の内容で保存します。
.env_sample

REACT_APP_AWS_API_ENDPOINT_MAIN="https://xxxxxxxxxx"


src/index.tsx に以下を追記します。
src/index.tsx

import reportWebVitals from './reportWebVitals';
// ----- 追加↓
import { Amplify } from 'aws-amplify';
import awsExports from './aws-exports';
Amplify.configure(awsExports);
// ----- 追加↑

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);


Home.tsx を API で取得したデータを表示するように変更します。
src/pages/Home.tsx

import React, { useEffect, useState } from 'react'
import { API } from 'aws-amplify'

type SampleDataType = [
  {
    id: string;
    name: string;
  }
];
const initialSampleData = {id: "", name: ""};

const Home: React.FC = () => {
  const [sampleData, setSampleData] = useState<SampleDataType>([initialSampleData])

  useEffect(() => {
    getSampleData()
  }, [])

  const getSampleData = async () => {
    try {
      const apiName = 'MainApi';
      const path = '/';
      const myInit = {};
    
      const data = await API.get(apiName, path, myInit);
      setSampleData(data)
    } catch (err) { console.log('error getting data') }
  }

  return (
    <div className="App">
      <p>ようこそ!</p>
      <p>登録データ一覧</p>
      {
        sampleData.map((data, index) => (
          <div key={data.id ? data.id : index}>
            <p>{data.name}</p>
          </div>
        ))
      }
    </div>
  );
}

export default Home;


tutorial-app-front ディレクトリでアプリを実行します。

npm start


ブラウザで F12 を押下して、開発者ツールを見るとエラーが出ています。


API 呼び出しをするには CORS 設定が必要なので、バックエンド側の修正を行っていきます。
参考
オリジン間リソース共有 (CORS) - HTTP | MDN

2-5. バックエンドの CORS 設定

VSCode のターミナルで作業します。
ここからは、バックエンド用ディレクトリ(C:\work\tutorial-app\tutorial-app-back)にいる前提で進めていきます。


REST API で CORS 設定をするには Lambda のソースコードのレスポンスを修正する必要があります。
参考
REST API リソースの CORS を有効にする - Amazon API Gateway


src/handlers 内の「get-all-items.js」「get-by-id.js」「put-item.js」それぞれの「response」を指定している部分に、「headers」を追加します。

src/handlers/get-all-items.js
src/handlers/get-by-id.js
src/handlers/put-item.js

    const response = {
        statusCode: 200,
// ----- 追加↓
        headers: {
            "Access-Control-Allow-Headers" : "Content-Type",
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET"
        },
// ----- 追加↑
        body: JSON.stringify(items)
    };


API Gateway にも CORS 設定をしておきます。
template.yaml の API Gateway 設定に「Cors」を追加します。

template.yaml

  # --------------------
  # API Gateway
  # --------------------
  SampleApi:
    Type: AWS::Serverless::Api
    Properties:
      Name: "tutorial-app-api"
      StageName: dev
      OpenApiVersion: 3.0.2
      EndpointConfiguration: REGIONAL
# ----- 追加↓
      Cors:
        AllowMethods: "'GET,POST,DELETE,PATCH,OPTIONS'"
        AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
        AllowOrigin: "'*'"
# ----- 追加↑


ビルド / デプロイをします。

sam build
sam deploy --config-env dev


デプロイが終わったら、ブラウザで開いている React アプリを更新してみましょう。
※停止している場合は、 tutorial-app-front ディレクトリで npm start して起動してください

データが表示されます。


※開発者ツールを開いている場合に表示されるこのエラーは、ログインページを実装する際に対応されるので今は気にしないで大丈夫です。


バックエンド / フロントエンド ともに push しておきましょう。

tutorial-app-front ディレクトリで

git add .
git commit -m "API 呼び出し追加"
git push origin main

tutorial-app-back ディレクトリで

git add .
git commit -m "CORS 設定追加"
git push origin main


React アプリから、自作した API を実行することに成功しました。
次回は API への認証の追加と、ログインページを実装していきます。

3. 参考

Adding TypeScript | Create React App
Tutorial - Set up fullstack project - React - AWS Amplify Docs