LambdaとDynamoDBでCRUDするWebアプリの構築

awsアプリケーション開発

こんにちは、ITエンジニアのz_a_k_iです!^^

今回はクライアントから送信されたデータをLambdaでDynamoDBに登録・更新するWebアプリを作成します。

以下の記事でLambdaを利用したWebアプリを作成しました。

今回はこちらで作成したWebアプリをベースに、DynamoDBと連携したサーバレスアプリケーションを作成します。

LambdaでDynamoDBにデータ登録するプログラム

作成するWebアプリ

作成するWebアプリは以下となります。データを登録・更新するアプリです。

データを登録・更新するアプリのため、検索結果の見た目が表示からテキストボックスに変更されてます。

各行の「更新」ボタンをクリックすることで行単位でデータを更新することが可能です。また、最下部にデータを登録する機能を追加しています。(見た目は次回の記事で整えます。)

登録対象のテーブル

登録対象のテーブルは変わりません。前回と同様に以下となります。

Lambdaの作成

前回作成したLambdaはデータ検索用のLambdaのため、データ登録・更新用のLambdaを新しく作成します。

マネジメントコンソール上で以下の設定でLambdaを作成します。

関数名は「updateUserData」とし、Pythonで作成していきます。

以下のコードで作成します。

import boto3
from boto3.dynamodb.conditions import Key

# DynamoDBリソースの初期化
dynamodb = boto3.resource('dynamodb')

def lambda_handler(event, context):
    # リクエストパラメータの取得
    parameters = event['queryStringParameters']
    user_id = parameters['id']
    user_name = parameters['name']
    user_age = parameters['age']
    user_email = parameters['email']
    
    # user-tableへの参照
    table = dynamodb.Table('user-table')
    
    # DynamoDBにデータが存在するか確認
    response = table.get_item(Key={'id': user_id})
    
    # データが存在する場合は更新、存在しない場合は新規登録
    if 'Item' in response:
        # データの更新
        table.update_item(
            Key={'id': user_id},
            UpdateExpression='SET #name = :name, #age = :age, #email = :email',
            ExpressionAttributeNames={
                '#name': 'name',
                '#age': 'age',
                '#email': 'email'
            },
            ExpressionAttributeValues={
                ':name': user_name,
                ':age': user_age,
                ':email': user_email
            }
        )
    else:
        # 新規データの登録
        table.put_item(
            Item={
                'id': user_id,
                'name': user_name,
                'age': user_age,
                'email': user_email
            }
        )
    
    return {
        'statusCode': 200,
        'body': 'データの登録または更新に成功しました。'
    }

DynamoDBのテーブルを操作するので、ロールを付与します。

前回と同様に、とりあえず、DBFullAccessの権限を設定します。

作成したLambdaの実行確認

テストタブをクリックし、イベントJSONに以下を貼り付け実行してみます。

{
  "queryStringParameters": {
    "id": "A00010",
    "name": "テスト",
    "age": "22",
    "email": "aaa@eaaa.aaa"
  }
}

[テスト」ボタンをクリックし、結果が以下となれば成功です。

念の為、DynamoDBのテーブルも見て、データが登録されてるかも確認してみます。

テストで登録した「A00010」のデータがちゃんと登録されています。

Lambdaの公開

API Gatewayの設定

作成したLambdaのコードを外部に公開するために、API Gatewayを設定していきます。
前回作成したAPIにリソースを追加していきます。

「/」を選択し、「リソースを作成」ボタンをクリックします。

「update-user-data」という名前でリソースを作成します。

メソッドタイプに「POST」を選択し、上で作成したLambdaを選択します。
設定後、画面下部にある「メソッドを作成」ボタンをクリックします。

次はCORSを有効化します。

対象のリソースを選択し、「CORSを有効化にする」ボタンをクリックします。

以下の設定で「保存」ボタンをクリックします。

API Gatewayのデプロイ

「APIをデプロイ」ボタンをクリックし、作成したAPIを公開します。

公開するステージはこれまでと同様「test」としてます。


Lambdaを呼び出すフロントエンド

フロントエンドアプリの作成

データ登録・更新ができるUIに変更します。

また、登録ボタン、更新ボタン押下時には、上で作成した登録・更新用のAPIを呼び出すように変更します。

コードは以下となります。APIのURLは実際のエンドポイントに書き換えてください。

import React, { useState } from 'react';
import axios from 'axios';
import './App.css';

function App() {
  const [name, setName] = useState('');
  const [results, setResults] = useState([]);
  const [updateStatus, setUpdateStatus] = useState({});
  const [registStatus, setRegistStatus] = useState('');

  const handleSearch = async () => {
    // 処理結果をクリア
    setUpdateStatus({});

    try {
      const response = await axios({
        method: 'post',
        url: 'https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/get-user-data',
        data: {
          queryStringParameters: {
            name: name
          }
        }
      });
      const usersData = JSON.parse(response.data.body);
      const editableUsersData = usersData.map(user => ({
        ...user,
        editId: user.id,
        editName: user.name,
        editAge: user.age,
        editEmail: user.email
      }));
      setResults(editableUsersData);
    } catch (error) {
      console.error('検索中にエラーが発生しました:', error);
    }
  };

  const handleEdit = (index, field, value) => {
    const updatedResults = [...results];
    updatedResults[index][field] = value;
    setResults(updatedResults);
  };

  // 更新ボタンの処理
  const handleUpdate = async (index) => {
    const user = results[index];
    try {
      const response = await axios({
        method: 'post',
        url: 'https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/update-user-data', // 実際のエンドポイントURLに置き換えてください
        data: {
          queryStringParameters: {
            id: user.editId,
            name: user.editName,
            age: user.editAge,
            email: user.editEmail
          }
        }
      });
      // 処理結果を状態にセット
      setUpdateStatus({ ...updateStatus, [index]: '処理が正常終了しました' });
    } catch (error) {
      // エラー処理
      setUpdateStatus({ ...updateStatus, [index]: 'エラーが発生しました' });
    }
  };

  // 新しいデータを登録するための状態
  const [newUser, setNewUser] = useState({
    newName: '',
    newAge: '',
    newEmail: ''
  });

  // 新しいデータの入力を処理する関数
  const handleNewUserChange = (field, value) => {
    setNewUser({ ...newUser, [field]: value });
  };

  // 新しいデータを登録する関数
  const handleRegister = async () => {
    setRegistStatus('');
    try {
      const response = await axios({
        method: 'post',
        url: 'https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/update-user-data', // 実際のエンドポイントURLに置き換えてください
        data: {
          queryStringParameters: {
            id: newUser.newId,
            name: newUser.newName,
            age: newUser.newAge,
            email: newUser.newEmail
          }
        }
      });
      // 登録成功時の処理
      console.log('データが正常に登録されました。', response);
      // 処理結果を状態にセット
      setRegistStatus('処理が正常終了しました');
    } catch (error) {
      // 登録失敗時のエラー処理
      console.error('データ登録中にエラーが発生しました。', error);
    }
  };

  return (
    <div>
      <div>
        <h2>検索条件</h2>
        <div>
          <label htmlFor="name">名前:</label>
          <input
            type="text"
            id="name"
            value={name}
            onChange={(e) => setName(e.target.value)}
            onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
          />
        </div>
      </div>
      <div>
        <h2>検索結果</h2>
        <ul className="results-list">
        {results.map((user, index) => (
          <li key={index}>
            <label>ID:</label>
            <input
              type="text"
              value={user.editId}
              disabled
              readOnly="true"
              onChange={(e) => handleEdit(index, 'editId', e.target.value)}
            />
            <label>名前:</label>
            <input
              type="text"
              value={user.editName}
              onChange={(e) => handleEdit(index, 'editName', e.target.value)}
            />
            <label>年齢:</label>
            <input
              type="number"
              value={user.editAge}
              onChange={(e) => handleEdit(index, 'editAge', e.target.value)}
            />
            <label>メール:</label>
            <input
              type="email"
              value={user.editEmail}
              onChange={(e) => handleEdit(index, 'editEmail', e.target.value)}
            />
            <button onClick={() => handleUpdate(index)}>更新</button>
            <span>{updateStatus[index]}</span>
          </li>
        ))}
      </ul>
      </div>
      <h2>データ登録</h2>
      <div>
      <label>ID:</label>
        <input
          type="text"
          value={newUser.newId}
          onChange={(e) => handleNewUserChange('newId', e.target.value)}
        />
        <label>名前:</label>
        <input
          type="text"
          value={newUser.newName}
          onChange={(e) => handleNewUserChange('newName', e.target.value)}
        />
        <label>年齢:</label>
        <input
          type="number"
          value={newUser.newAge}
          onChange={(e) => handleNewUserChange('newAge', e.target.value)}
        />
        <label>メール:</label>
        <input
          type="email"
          value={newUser.newEmail}
          onChange={(e) => handleNewUserChange('newEmail', e.target.value)}
        />
        <button onClick={handleRegister}>登録</button>
        <span>{registStatus}</span>
      </div>
    </div>
  );
}

export default App;

Webアプリのテスト

ローカルPC上でReactを起動します。VSCodeのターミナル上で以下コマンドを実行します。

npm start

画面が起動し、検索、更新、登録ができれば成功です。

まとめ

LambdaでDynamoDBにデータ登録するWebアプリのまとめ

本記事では、AWS LambdaとDynamoDBを利用してデータを登録・更新するWebアプリの構築方法を紹介しました。

前回の記事と合わせてLambda、DynamoDBといったサーバーレスサービスのみでデータの検索登録更新ができるWebアプリを構築することができました。

次回は本記事の内容をベースに、画面のデザインを整えて使い勝手の良いシステムに変更する方法をご紹介していきます。

皆様の参考になりましたら幸いです。

コメント

タイトルとURLをコピーしました