Tips & Tricks

Claude Code で REST API を作ってみよう|初心者でもわかる実践入門

REST APIの基礎をClaude Codeと一緒に学ぶ入門ガイド。エンドポイント設計からバリデーション・エラーハンドリングまで、コピペで動くコードで丁寧に解説。

「REST APIって何から始めればいいかわからない」——私も最初はそうでした。

ドキュメントを読んでも抽象的すぎて、結局何を作ればいいのか。そんな時に Claude Code を使い始めて、「とにかく動くものを作りながら学ぶ」 というアプローチが一番速いと気づきました。

この記事では、REST API の基礎知識ゼロから始めて、実際に動くAPIを作るまでを Claude Code と一緒にやっていきます。コードはすべてコピペで動くレベルで書いています。


REST API とは何か (3行で)

REST API とは、ウェブ上のリソース (データ) を HTTP で操作するための取り決めです。

ブラウザ/アプリ  →  HTTP リクエスト  →  サーバー (API)
                ←  JSON レスポンス  ←

例えば、ユーザー情報を管理するAPIなら:

やりたいことHTTP メソッドURL
ユーザー一覧を取得GET/users
特定ユーザーを取得GET/users/123
ユーザーを作成POST/users
ユーザーを更新PUT/users/123
ユーザーを削除DELETE/users/123

これだけ理解できれば、Claude Code と一緒に作り始められます。


環境セットアップ

今回は Hono (軽量WebフレームワークのTypeScript版) を使います。Express より型安全で、Claude Code との相性も抜群です。

mkdir my-first-api
cd my-first-api
npm init -y
npm install hono
npm install -D typescript @types/node ts-node
npx tsc --init

src/index.ts を作成して Claude Code に聞きます:

claude -p "
Hono を使った REST API のボイラープレートを src/index.ts に作って。
- ポート3000でサーバー起動
- ヘルスチェック用の GET /health エンドポイント
- JSON を返す設定
実行コマンドは npx ts-node src/index.ts
"

Claude Code が以下のようなコードを生成してくれます:

// src/index.ts
import { Hono } from "hono";
import { serve } from "@hono/node-server";

const app = new Hono();

app.get("/health", (c) => {
  return c.json({ status: "ok", timestamp: new Date().toISOString() });
});

serve({ fetch: app.fetch, port: 3000 }, () => {
  console.log("Server running at http://localhost:3000");
});
npx ts-node src/index.ts
# → Server running at http://localhost:3000

curl http://localhost:3000/health
# → {"status":"ok","timestamp":"2026-04-27T07:30:00.000Z"}

動きましたか? これが REST API の出発点です。


Step 1: 基本的なCRUDを作る

次に、Todoリストを管理するAPIを作ります。Claude Code に頼みましょう。

claude -p "
src/index.ts に Todo の CRUD エンドポイントを追加して。
- GET  /todos         — 一覧取得
- GET  /todos/:id     — 1件取得
- POST /todos         — 作成 (title: string 必須)
- PUT  /todos/:id     — 更新 (title: string)
- DELETE /todos/:id   — 削除

データはメモリ上の配列で管理。
Todo の型は { id: string, title: string, done: boolean, createdAt: string }
id は crypto.randomUUID() で生成
"

生成されるコード:

import { Hono } from "hono";
import { serve } from "@hono/node-server";

const app = new Hono();

// メモリ上のデータストア
type Todo = { id: string; title: string; done: boolean; createdAt: string };
let todos: Todo[] = [];

// 一覧取得
app.get("/todos", (c) => c.json(todos));

// 1件取得
app.get("/todos/:id", (c) => {
  const todo = todos.find((t) => t.id === c.req.param("id"));
  if (!todo) return c.json({ error: "Not found" }, 404);
  return c.json(todo);
});

// 作成
app.post("/todos", async (c) => {
  const body = await c.req.json();
  if (!body.title) return c.json({ error: "title is required" }, 400);
  const todo: Todo = {
    id: crypto.randomUUID(),
    title: body.title,
    done: false,
    createdAt: new Date().toISOString(),
  };
  todos.push(todo);
  return c.json(todo, 201);
});

// 更新
app.put("/todos/:id", async (c) => {
  const idx = todos.findIndex((t) => t.id === c.req.param("id"));
  if (idx === -1) return c.json({ error: "Not found" }, 404);
  const body = await c.req.json();
  todos[idx] = { ...todos[idx], ...body };
  return c.json(todos[idx]);
});

// 削除
app.delete("/todos/:id", (c) => {
  const idx = todos.findIndex((t) => t.id === c.req.param("id"));
  if (idx === -1) return c.json({ error: "Not found" }, 404);
  todos.splice(idx, 1);
  return c.json({ message: "Deleted" });
});

serve({ fetch: app.fetch, port: 3000 }, () => {
  console.log("Server running at http://localhost:3000");
});

試してみましょう:

# Todo を作成
curl -X POST http://localhost:3000/todos \
  -H "Content-Type: application/json" \
  -d '{"title": "Claude Codeを試す"}'

# 一覧取得
curl http://localhost:3000/todos

# 削除 (id は上で返ってきたものを使う)
curl -X DELETE http://localhost:3000/todos/<id>

Step 2: バリデーションを追加する

「title が空でも作れてしまう」「id が UUID 形式じゃなくてもアクセスできる」— こういった問題をバリデーションで防ぎます。Claude Code に頼みましょう。

claude -p "
zod を使って POST /todos と PUT /todos/:id のバリデーションを追加して。
- title: 1文字以上100文字以下の文字列
- done: (PUT のみ) boolean
バリデーション失敗時は 400 エラーと具体的なエラーメッセージを返す
"
npm install zod

Claude Code が zod スキーマを追加してくれます:

import { z } from "zod";

const CreateTodoSchema = z.object({
  title: z.string().min(1, "タイトルは1文字以上").max(100, "タイトルは100文字以内"),
});

const UpdateTodoSchema = z.object({
  title: z.string().min(1).max(100).optional(),
  done: z.boolean().optional(),
});

// POST /todos (バリデーション付き)
app.post("/todos", async (c) => {
  const body = await c.req.json().catch(() => ({}));
  const result = CreateTodoSchema.safeParse(body);
  if (!result.success) {
    return c.json({ error: result.error.flatten().fieldErrors }, 400);
  }
  const todo: Todo = {
    id: crypto.randomUUID(),
    title: result.data.title,
    done: false,
    createdAt: new Date().toISOString(),
  };
  todos.push(todo);
  return c.json(todo, 201);
});

バリデーションエラーの確認:

# title なしで作成 → エラーになるはず
curl -X POST http://localhost:3000/todos \
  -H "Content-Type: application/json" \
  -d '{}'
# → {"error":{"title":["タイトルは1文字以上"]}}

Step 3: エラーハンドリングを整える

今のコードは各エンドポイントでバラバラにエラーを返しています。Claude Code に統一してもらいましょう。

claude -p "
エラーハンドリングを統一して。
- 共通のエラーレスポンス形式: { error: { code: string, message: string } }
- 404: NOT_FOUND
- 400: VALIDATION_ERROR  
- 500: INTERNAL_SERVER_ERROR
グローバルエラーハンドラーを Hono の onError で実装
"
// エラー型の定義
class AppError extends Error {
  constructor(
    public code: string,
    public message: string,
    public statusCode: number = 400
  ) {
    super(message);
  }
}

// グローバルエラーハンドラー
app.onError((err, c) => {
  if (err instanceof AppError) {
    return c.json(
      { error: { code: err.code, message: err.message } },
      err.statusCode as any
    );
  }
  console.error(err);
  return c.json(
    { error: { code: "INTERNAL_SERVER_ERROR", message: "予期しないエラーが発生しました" } },
    500
  );
});

// 使い方
app.get("/todos/:id", (c) => {
  const todo = todos.find((t) => t.id === c.req.param("id"));
  if (!todo) throw new AppError("NOT_FOUND", "指定したTodoが見つかりません", 404);
  return c.json(todo);
});

Step 4: Swagger UIでドキュメントを自動生成

APIを作ったら、ドキュメントも必要です。Claude Code に頼めば数分で完成します。

claude -p "
@hono/swagger-ui と @hono/zod-openapi を使って
Swagger UI を /docs に追加して。
既存のエンドポイントに OpenAPI スキーマを追加して
"
npm install @hono/swagger-ui @hono/zod-openapi

完成したら http://localhost:3000/docs にアクセスするとAPIドキュメントが表示されます。


Claude Code との API 開発の流れ (まとめ)

私が実際にやっている開発フローです。

1. 「こういうAPIが欲しい」とClaude Codeに伝える
    ↓
2. 生成されたコードを確認・動作テスト
    ↓
3. 「ここを修正して」「バリデーションを追加して」と会話
    ↓
4. テスト通ったらgit commit

最初につまずいたポイント (実体験)

私が最初の API を作った時、エラーハンドリングを全部省略してしまい、後から追加するのに時間がかかりました。今は最初から「エラーハンドリングも含めて作って」と一言添えるだけで、最初からちゃんとしたコードが出てきます。Claude Code には 最初から要件を全部伝える のがコツです。


よくある落とし穴 3つ

落とし穴1: JSONのパースエラーを無視する

// ❌ エラーが起きてもわからない
const body = await c.req.json();

// ✅ パース失敗を捕まえる
const body = await c.req.json().catch(() => null);
if (!body) return c.json({ error: "Invalid JSON" }, 400);

落とし穴2: 404 と 400 を混同する

400: リクエストが間違っている (バリデーションエラー、必須項目なし)
404: リソースが存在しない (IDが見つからない)
422: リクエスト形式は正しいが処理できない

Claude Code に「404を返すべきか400を返すべきか」を聞くと、適切な判断をしてくれます。

落とし穴3: 全部メモリに持つ

この記事のコードはデモ用にメモリ配列を使っています。サーバーを再起動するとデータが消えます。本番では PostgreSQL や MongoDB などのDBが必要です。「メモリじゃなくてSQLiteに保存するようにして」とClaude Codeに頼めば移行してくれます。


次のステップ

REST API の基礎ができたら、次は以下を試してみてください。

ステップ内容
データベース連携SQLite → PostgreSQL (Prisma)
認証JWT トークン認証を追加
テストvitest でAPIテストを書く
デプロイVercel / Cloudflare Workers に公開

どれも「〇〇を追加して」とClaude Codeに頼めば、数分でベースが完成します。まず動くものを作ること——それが一番の近道です。

関連記事

#claude-code #rest-api #beginner #typescript #backend #tutorial
無料プレゼント

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

現役DX室長|Claude Code でゼロから多言語AI技術メディア運営中。実務直結の自動化、AI開発相談・研修受付中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。