家計簿アプリを作る #4:収支の登録フォームを実装する
家計簿アプリ作成シリーズの第4回です。今回は SvelteKit の Form Actions を使って収支の登録フォームを実装します。
ファイル構成
src/routes/
transactions/
new/
+page.server.ts # 新規作成:Form Action でデータを登録
+page.svelte # 新規作成:登録フォーム
登録フォームは /transactions/new に配置しました。後々 /transactions で一覧、/transactions/[id] で詳細・編集と自然に拡張できる構成です。
+page.server.ts:Form Action を実装する
import { fail, redirect } from '@sveltejs/kit';
import type { Actions } from './$types';
import { createDb } from '$lib/server/db';
import { transactions } from '$lib/server/db/schema';
export const actions: Actions = {
create: async ({ request, platform }) => {
const formData = await request.formData();
const amount = formData.get('amount');
const type = formData.get('type');
const category = formData.get('category');
const memo = formData.get('memo') || '';
const date = formData.get('date');
if (!amount || !type || !category || !date) {
return fail(400, { error: 'All fields except memo are required.' });
}
const db = createDb(platform!.env.DB);
await db.insert(transactions).values({
amount: Number(amount),
type: String(type),
category: String(category),
memo: String(memo),
date: String(date)
});
redirect(303, '/');
}
};
ポイント:
formData.get()の戻り値はFormDataEntryValue | nullなので、必須項目はif (!amount || ...)でバリデーションする- バリデーションエラーは
fail(400, { error: '...' })で返すと、フォーム側で受け取れる memoは任意入力のため|| ''でデフォルト空文字にしている- Drizzle の
db.insert().values()でデータを挿入する - 登録後は
redirect(303, '/')でトップページへ戻る
+page.svelte:登録フォームを作る
<script lang="ts">
import { enhance } from "$app/forms";
let { form } = $props();
</script>
<form method="POST" action="?/create" use:enhance>
<label>
金額:
<input type="number" name="amount" required />
</label>
<label>
種類:
<select name="type" required>
<option value="income">収入</option>
<option value="expense">支出</option>
</select>
</label>
<label>
カテゴリ:
<input type="text" name="category" required />
</label>
<label>
メモ:
<input type="text" name="memo" />
</label>
<label>
日付:
<input type="date" name="date" required />
</label>
<button type="submit">追加</button>
{#if form?.error}
<p style="color: red">{form.error}</p>
{/if}
</form>
ポイント:
use:enhanceで JavaScript が有効な環境ではページ全体のリロードなしに送信できるaction="?/create"で+page.server.tsのcreateアクションを呼び出すform?.errorでサーバーから返ったエラーメッセージを表示する
動作確認
npm run dev で起動後、http://localhost:5173/transactions/new にアクセスしてフォームから登録し、トップページの一覧に反映されることを確認します。
まとめ
| ポイント | 内容 |
|---|---|
| URL 設計 | /transactions/new に配置。後の拡張を見越した構成 |
| Form Actions | export const actions に関数を定義する |
| バリデーション | fail(400, {...}) でエラーをフォームに返す |
| データ挿入 | db.insert(transactions).values({...}) |
| リダイレクト | redirect(303, '/') でトップへ戻る |
use:enhance |
ページリロードなしでフォーム送信できる |
次回は収支の削除・編集を実装します。