GPT4が作成してくれたAWS Serverless TODOアプリケーションを作成するチュートリアル
シンプルな TODO アプリチュートリアル
このチュートリアルでは、シンプルな TODO アプリケーションを作成します。技術要素としてバックエンドには AWS SAM, API Gateway, AWS Lambda, DynamoDB, Node.js を、フロントエンドには React.js を使用します。
目次
環境の準備
必要なソフトウェアのインストール
このチュートリアルでは、以下のソフトウェアがインストールされていることを前提にしています。
これらのソフトウェアがインストールされていない場合は、公式ドキュメントに従ってインストールしてください。
AWS 設定
AWS CLI がインストールされていることを確認したら、次に AWS アカウントを設定します。ターミナルで以下のコマンドを実行してください。
aws configure
アクセスキー、シークレットアクセスキー、リージョン、出力形式を入力します。リージョンは、このチュートリアルで使用する AWS サービスが利用可能なリージョンを指定してください。例えば、us-east-1
や ap-northeast-1
などです。
バックエンドの構築
プロジェクトの初期化
まず、プロジェクト用のディレクトリを作成し、その中に移動します。
mkdir simple-todo-app cd simple-todo-app
次に、AWS SAM CLI を使用してバックエンド用のプロジェクトを初期化します。
sam init --runtime nodejs14.x --name backend cd backend
テンプレートファイルの編集
template.yaml
ファイルを開き、以下のように編集してください。
Resources: TodosTable: Type: AWS::DynamoDB::Table Properties: TableName: Todos AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 5 WriteCapacityUnits: 5 GetTodosFunction: Type: AWS::Serverless::Function Properties: CodeUri: src/ Handler: getTodos.handler Runtime: nodejs14.x Environment: Variables: TODOS_TABLE: !Ref TodosTable Events: GetTodosApi: Type: Api Properties: Path: /todos Method: GET CreateTodoFunction: Type: AWS::Serverless::Function Properties: CodeUri: src/ Handler: createTodo.handler Runtime: nodejs14.x Environment: Variables: TODOS_TABLE: !Ref TodosTable Events: CreateTodoApi: Type: Api Properties: Path: /todos Method: POST UpdateTodoFunction: Type: AWS::Serverless::Function Properties: CodeUri: src/ Handler: updateTodo.handler Runtime: nodejs14.x Environment: Variables: TODOS_TABLE: !Ref TodosTable Events: UpdateTodoApi: Type: Api Properties: Path: /todos/{id} Method: PUT DeleteTodoFunction: Type: AWS::Serverless::Function Properties: CodeUri: src/ Handler: deleteTodo.handler Runtime: nodejs14.x Environment: Variables: TODOS_TABLE: !Ref TodosTable Events: DeleteTodoApi: Type: Api Properties: Path: /todos/{id} Method: DELETE Outputs: TodosApi: Description: API Gateway endpoint URL for the todos Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/todos/" TodosTable: Description: DynamoDB table for storing todos Value: !Ref TodosTable
これにより、DynamoDB テーブルの作成と、各エンドポイントに対応する Lambda 関数が定義されます。
Lambda 関数の実装
src
ディレクトリに移動し、以下の JavaScript ファイルを作成して、それぞれの Lambda 関数のコードを実装します。
getTodos.js
const AWS = require("aws-sdk") const dynamo = new AWS.DynamoDB.DocumentClient() exports.handler = async (event) => { const params = { TableName: process.env.TODOS_TABLE, } const result = await dynamo.scan(params).promise() return { statusCode: 200, body: JSON.stringify(result.Items), } }
createTodo.js
const AWS = require("aws-sdk") const dynamo = new AWS.DynamoDB.DocumentClient() const uuid = require("uuid") exports.handler = async (event) => { const data = JSON.parse(event.body) const params = { TableName: process.env.TODOS_TABLE, Item: { id: uuid.v1(), title: data.title, details: data.details, dueDate: data.dueDate, completed: false, }, } await dynamo.put(params).promise() return { statusCode: 200, body: JSON.stringify(params.Item), } }
updateTodo.js
const AWS = require("aws-sdk") const dynamo = new AWS.DynamoDB.DocumentClient() exports.handler = async (event) => { const data = JSON.parse(event.body) const id = event.pathParameters.id const params = { TableName: process.env.TODOS_TABLE, Key: { id: id, }, UpdateExpression: "SET title = :title, details = :details, dueDate = :dueDate, completed = :completed", ExpressionAttributeValues: { ":title": data.title, ":details": data.details, ":dueDate": data.dueDate, ":completed": data.completed, }, ReturnValues: "ALL_NEW", } const result = await dynamo.update(params).promise() return { statusCode: 200, body: JSON.stringify(result.Attributes), } }
deleteTodo.js
const AWS = require("aws-sdk") const dynamo = new AWS.DynamoDB.DocumentClient() exports.handler = async (event) => { const id = event.pathParameters.id const params = { TableName: process.env.TODOS_TABLE, Key: { id: id, }, } await dynamo.delete(params).promise() return { statusCode: 200, body: JSON.stringify({message: "Todo deleted successfully"}), } }
これでバックエンドの実装が完了しました。
フロントエンドの構築
React アプリの作成
プロジェクトのルートディレクトリに戻り、React のプロジェクトを作成します。
cd .. npx create-react-app frontend
必要なパッケージのインストール
axios
をインストールして、API と通信できるようにします。
cd frontend npm install axios
コンポーネントの作成
src
ディレクトリ内に、以下のコンポーネントを作成します。
TodoList.js
import React, {useState, useEffect} from "react" import axios from "axios" const TodoList = () => { const [todos, setTodos] = useState([]) useEffect(() => { getTodos() }, []) const getTodos = async () => { const response = await axios.get("<API_ENDPOINT>") setTodos(response.data) } return ( <div> {todos.map((todo) => ( <div key={todo.id}> <h2>{todo.title}</h2> <p>{todo.details}</p> <p>{todo.dueDate}</p> </div> ))} </div> ) } export default TodoList
注: <API_ENDPOINT>
をバックエンドの API エンドポイントに置き換えてください。
TodoForm.js
import React, {useState} from "react" import axios from "axios" const TodoForm = () => { const [title, setTitle] = useState("") const [details, setDetails] = useState("") const [dueDate, setDueDate] = useState("") const handleSubmit = async (e) => { e.preventDefault() const newTodo = { title: title, details: details, dueDate: dueDate, } await axios.post("<API_ENDPOINT>", newTodo) setTitle("") setDetails("") setDueDate("") } return ( <form onSubmit={handleSubmit}> <label>Title:</label> <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} /> <label>Details:</label> <input type="text" value={details} onChange={(e) => setDetails(e.target.value)} /> <label>Due Date:</label> <input type="date" value={dueDate} onChange={(e) => setDueDate(e.target.value)} /> <button type="submit">Add Todo</button> </form> ) } export default TodoForm
注: <API_ENDPOINT>
をバックエンドの API エンドポイントに置き換えてください。
コンポーネントの組み込み
src/App.js
を開いて、以下のように編集してください。
import React from "react" import TodoList from "./TodoList" import TodoForm from "./TodoForm" function App() { return ( <div> <h1>Simple Todo App</h1> <TodoForm /> <TodoList /> </div> ) } export default App
これでフロントエンドの実装が完了しました。
デプロイ
バックエンドのデプロイ
バックエンドのディレクトリに移動し、以下のコマンドを実行して AWS にデプロイします。
cd backend sam build sam deploy --guided
デプロイが完了したら、API エンドポイントをメモしておいてください。
フロントエンドのデプロイ
フロントエンドのディレクトリに移動し、以下のコマンドを実行してビルドします。
cd ../frontend npm run build
ビルドが完了したら、build
ディレクトリを適当のウェブサーバーにアップロードしてデプロイします。例えば、Amazon S3 に静的ウェブサイトとしてホスティングすることができます。詳細については、公式ドキュメントを参照してください。
これでシンプルな TODO アプリケーションが完成しました。フロントエンドの URL にアクセスして、タスクの追加、表示、編集、削除、完了を試してみてください。
まとめ
このチュートリアルでは、AWS SAM, API Gateway, AWS Lambda, DynamoDB, Node.js を使用したバックエンドと、React.js を使用したフロントエンドで構成されるシンプルな TODO アプリケーションを作成しました。
これを参考に、さまざまな AWS サービスや React.js を使用して、より複雑なアプリケーションを開発することができます。また、このチュートリアルでは触れていませんが、セキュリティやパフォーマンスの向上、CI/CD の導入、エラーハンドリングなど、本番環境にデプロイする際には検討すべき要素がさらにあります。
最後に、このチュートリアルが初心者にもわかりやすく、ソースコードとディレクトリ構造が理解しやすい形で提供されていることを目指して作成しました。今後も技術要素を学びながら、より良いアプリケーション開発に役立ててください。