こんにちは。 アドベントカレンダー21日目です。終盤に差し掛かってきました。 今年はフロントエンドまわりであれこれ開発することが多かったので、振り返りを兼ねてこれからフロントエンド開発を始める方向けに入門編としてお送りしています。 最終日の25日には何かアプリケーションができていることが目標です。
↓最初から読み始めたい方はこちらか↓
おさらい
- Visual Studio Codeを使ったReactの開発環境の構築(第1回)
- CSSフレームワークの1つであるtailwindcssを使ったUI開発(第2回)
- コンポーネント化(第3回)
- フォーマッター(第4回)
- Linter(第5回)
- バージョン管理(第6回)
- 状態管理とReact hook form(第7回、第8回、第11回))
- Visual Studio Codeの設定(第9回、第10回、第16回、第17回)
- Reactルーティング(第12回)
- Playwright(第13回、第14回)
- GitHub CodespacesでAmplify
- 環境立ち上げとCLIツールの有効化(第15回)
- Amplifyで初期プロジェクト作成(第18回)
- Amplifyで認証機能作成(第19回)
- AmplifyでAPI機能作成(第20回)
今回のはなし
第18回からAmplifyシリーズでお送りしています。前回のAPI機能を作成する際にテーマ性を持ってやろう、と決めて「書籍管理アプリ」を作ることにしました。今回は実際にAPI機能を使って書籍情報を登録する処理を作ってみましょう。
準備
これまでの記事であれこれ追加したものを1度綺麗にお掃除しました。以下のようなディレクトリ構成に変更しています。
$ tree ./pages/ ./pages/ ├── app.css ├── _app.tsx ├── book │ └── resister.tsx └── index.tsx
画面UIの作成
まずは登録フォームの画面から作成していきましょう。これまでに触れた内容ですのでコードの細かい解説は省略します。次のサンプルコードをpages/book/resister.tsx
に貼り付けてください。
まだ具体的な処理を書いていませんが、登録ボタンを押すとコンソールログに送信内容が表示されるようにしています。
サンプルコードはこちら
"use client";
import { CreateBookInput } from "@/src/API";
import { useFieldArray, useForm } from "react-hook-form";
type AutherInputs = {
name: CreateBookInput["name"];
}
type Inputs = {
name: CreateBookInput["name"];
authers: AutherInputs[];
publisher: CreateBookInput["publisher"];
};
export default function BookResister() {
const { register, control, handleSubmit, formState: {
isValid,
isDirty,
isSubmitting,
} } = useForm<Inputs>({
mode: "onChange",
defaultValues: {
name: "",
authers: [],
publisher: "",
},
});
const { fields, append, remove } = useFieldArray({
control,
name: "authers",
});
const onSubmit = (data: Inputs) => {
console.log(data);
}
return (
<div className="p-5 container mx-auto md">
<h3 className="text-3xl font-bold dark:text-white">書籍登録</h3>
<div>
<div>
<label
htmlFor="book_name"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
書籍名
</label>
<input
id="book_name"
type="text"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="サンプルの本"
{...register("name", { required: true })}
/>
</div>
<div>
<label
htmlFor="author"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
著者
</label>
{fields.map((field, index) => (
<div
key={index}
className="flex"
>
<input
id="author"
type="text"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="著者"
{...register(`authers.${index}.name`, { required: true })}
/>
<button
type="button"
className="text-red-500 hover:text-red-700 whitespace-nowrap"
onClick={() => remove(index)}
>
削除
</button>
</div>
))}
<button
type="button"
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded"
onClick={() => append({ name: "" })}
>
著者を追加
</button>
</div>
<div>
<label
htmlFor="publisher"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
出版社
</label>
<input
id="publisher"
type="text"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="出版社"
{...register("publisher", { required: true })}
/>
</div>
<div>
<button
type="submit"
disabled={!isValid || !isDirty || isSubmitting}
className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-lg disabled:opacity-50"
onClick={handleSubmit(onSubmit)}
>
登録
</button>
</div>
</div>
</div>
)
}
コードを実行したときに表示される画面はこんな感じです。
登録処理の作成
画面UIの準備ができたら次は登録処理を実装してみましょう。前回Amplifyで作成したAPIと接続してデータ登録をします。
createBookData
という関数を1つ作ります。関数の中ではGraphQLを通じてDynamoDBにデータを登録する処理を記述しています。
import { Book, CreateBookInput, CreateBookMutation } from "@/src/API"; import { createBook } from "@/src/graphql/mutations"; import { GraphQLResult, generateClient } from "aws-amplify/api"; export default async function createBookData(input: CreateBookInput) { const client = generateClient(); const response = await client.graphql({ query: createBook, variables: { input }, }) as GraphQLResult<CreateBookMutation>; if (response.errors) { throw new Error(response.errors[0].message); } if (!response.data?.createBook) { throw new Error("Book not created"); } const book: Book = response.data?.createBook; return book; }
メインの処理はこの部分です。amplify pushした後にAPIクライアント ライブラリが自動で生成されるため、以下のように呼び出すだけでデータを登録する処理を書くことができます。
const client = generateClient(); const response = await client.graphql({ query: createBook, variables: { input }, }) as GraphQLResult<CreateBookMutation>;
それ以降の処理に関しては、レスポンス内容を取り扱いしやすいようにあれこれ加工しているところになります。今回はそこまで重要な処理ではないため、省略します。
コードが書けたので、実際に実行してみました。
画面上で適当な情報を入力したら、登録ボタンを押します。今回は、登録が成功したら登録されたデータをレスポンスとして返却されるようにしています。登録データの中でID項目はリクエストで指定していないので、レスポンス時に設定されていたら、無事にデータが登録されてユニークなIDが発行されたことになります。
レスポンス内容を見てみると無事にIDが設定されているので、登録に成功したようですね。
今日はこの辺で以上です。
おわりに
前回バックエンドにAPIを追加したので、今回はAPIを通じてDynamoDBにデータを登録する処理を書いてみました。次回は、登録したデータを取得して一覧表示するところをやっていきます。