第114章:練習:/api/todos に追加POSTする➕📝✨
今日は「TODOを追加するAPI」を作るよ〜!🎀
POST /api/todos に { title: "..." } を送ったら、新しいTODOが返ってくる状態にします💪😊
この章のゴール🎯
POST /api/todosを作れる✨- リクエストの body(JSON) を受け取れる📩
- 最低限のバリデーションができる🛡️
201 Createdで追加したTODOを返せる✅
まずは図でイメージしよ〜🧠🪄
実装:app/api/todos/route.ts に POST を追加する🛠️💖
第113章で
GETがある前提で、同じファイルにPOSTも足す感じでいくよ〜😊
✅ 完成形(GET + POST)
import { NextResponse } from "next/server";
type Todo = {
id: string;
title: string;
done: boolean;
createdAt: string;
};
// ※練習用:メモリ上のDB(開発サーバー再起動で消えるよ!)
const todos: Todo[] = [
{
id: "1",
title: "最初のTODO",
done: false,
createdAt: new Date().toISOString(),
},
];
export async function GET() {
return NextResponse.json({ todos });
}
export async function POST(req: Request) {
try {
// JSONが壊れてた時に落ちないようにする🌷
const body: unknown = await req.json().catch(() => null);
// 形チェック(ゆるく安全に)🛡️
if (
!body ||
typeof body !== "object" ||
!("title" in body) ||
typeof (body as any).title !== "string"
) {
return NextResponse.json(
{ error: "title は文字列で必須です 🥺" },
{ status: 400 }
);
}
const title = (body as any).title.trim();
if (title.length === 0) {
return NextResponse.json(
{ error: "title は空にできません 🥺" },
{ status: 400 }
);
}
if (title.length > 100) {
return NextResponse.json(
{ error: "title が長すぎます(100文字まで)🥺" },
{ status: 400 }
);
}
const todo: Todo = {
id: crypto.randomUUID(),
title,
done: false,
createdAt: new Date().toISOString(),
};
// 先頭に追加(新しい順)✨
todos.unshift(todo);
// 201 Created で、作ったTODOを返す🎉
return NextResponse.json({ todo }, { status: 201 });
} catch {
return NextResponse.json(
{ error: "サーバー側でエラーが起きました 🙇♀️" },
{ status: 500 }
);
}
}
動作確認:Windowsで叩いてみよう🎯💻
開発サーバー起動(すでに起動中ならOK)🚀
npm run dev
✅ 1) POSTで追加(curl)
curl -X POST http://localhost:3000/api/todos ^
-H "Content-Type: application/json" ^
-d "{\"title\":\"レポート提出\"}"
✅ 2) POSTで追加(PowerShell)
Invoke-RestMethod `
-Method Post `
-Uri "http://localhost:3000/api/todos" `
-ContentType "application/json" `
-Body '{"title":"ゼミの資料作る"}'
✅ 3) GETで一覧を見る
curl http://localhost:3000/api/todos
期待するレスポンス例🎁✨
POST成功(201)
{
"todo": {
"id": "(ランダムなUUID)",
"title": "レポート提出",
"done": false,
"createdAt": "2025-12-25T..."
}
}
titleが空(400)
{ "error": "title は空にできません 🥺" }
よくあるミスあるある🐣💥
Content-Type: application/jsonを付け忘れて、うまく読めない🌀req.json()を 2回呼んで「もう読めないよ!」ってなる(bodyは基本1回だけ)⚠️titleの前後スペースをトリムしてなくて、空文字が通っちゃう😵💫
ミニ練習(やってみよ〜!)🎀✨
titleが 重複してたら 409 を返す(任意)🚦doneも受け取りたいなら、booleanかチェックして反映してみる✅- レスポンスに
count(現在の件数)を入れてみる📦
これで 「追加POST」 できたよ〜!🎉➕ 次の章(第115章)で、エラーの型をちゃんと決めるとさらに美しくなる✨🧷