© TOOLS BOX — Next.js / React / TypeScript コードサンプル集

サンプルガイド
←サンプル一覧
nextjscrud

Prisma と Route Handler で CRUD API を実装する

Prisma Client の findMany / create / update / delete を Route Handler から呼び出して CRUD API を構築する例。スキーマ定義からマイグレーション・型安全なクエリまでを示す。

難易度: 中級·更新: 2026-04-18·
prisma

対応バージョン

nextjs 15react 19prisma 6

前提環境

Next.js Route Handler の基本と SQL の基礎を理解していること

概要

schema.prisma でモデルを定義し、prisma migrate でテーブルを作成、Route Handler から Prisma Client の findMany / create / update / delete を呼び出して型安全な CRUD API を構築する。nextjs-route-handler-crud のインメモリ実装を実際の DB 連携に置き換えるパターン。

インストール

npm install prisma @prisma/client
npx prisma init

実装

スキーマ定義

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

model User {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
# .env
DATABASE_URL="file:./dev.db"
# マイグレーション実行
npx prisma migrate dev --name init

Prisma Client シングルトン

// lib/prisma.ts
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };

export const prisma =
  globalForPrisma.prisma ?? new PrismaClient();

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

GET(一覧取得)・POST(作成)

// app/api/users/route.ts
import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";

export async function GET() {
  const users = await prisma.user.findMany({
    orderBy: { createdAt: "desc" },
  });
  return NextResponse.json(users);
}

export async function POST(request: Request) {
  let body: unknown;
  try {
    body = await request.json();
  } catch {
    return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
  }

  const { name, email } = body as { name?: string; email?: string };

  if (!name || !email) {
    return NextResponse.json({ error: "name and email are required" }, { status: 400 });
  }

  try {
    const user = await prisma.user.create({ data: { name, email } });
    return NextResponse.json(user, { status: 201 });
  } catch {
    return NextResponse.json({ error: "Email already exists" }, { status: 409 });
  }
}

GET(単件取得)・PATCH(更新)・DELETE(削除)

// app/api/users/[id]/route.ts
import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";

type Params = { params: Promise<{ id: string }> };

export async function GET(_request: Request, { params }: Params) {
  const { id } = await params;
  const user = await prisma.user.findUnique({ where: { id: Number(id) } });

  if (!user) {
    return NextResponse.json({ error: "User not found" }, { status: 404 });
  }
  return NextResponse.json(user);
}

export async function PATCH(request: Request, { params }: Params) {
  const { id } = await params;
  const body = await request.json() as { name?: string; email?: string };

  try {
    const user = await prisma.user.update({
      where: { id: Number(id) },
      data: body,
    });
    return NextResponse.json(user);
  } catch {
    return NextResponse.json({ error: "User not found" }, { status: 404 });
  }
}

export async function DELETE(_request: Request, { params }: Params) {
  const { id } = await params;

  try {
    await prisma.user.delete({ where: { id: Number(id) } });
    return new Response(null, { status: 204 });
  } catch {
    return NextResponse.json({ error: "User not found" }, { status: 404 });
  }
}

ポイント

  • lib/prisma.ts でシングルトンパターンを使う。globalThis に保存して next dev のホットリロード時に接続が重複しないようにする
  • prisma.user.create() の返り値は User 型(schema.prisma から自動生成)で型安全。id や createdAt の型を手動管理しなくてよい
  • @unique フィールドへの重複は Prisma が PrismaClientKnownRequestError(code P2002)をスローする。catch で補足して 409 を返す
  • nextjs-route-handler-crud との使い分け: インメモリで CRUD の構造を理解する場合は nextjs-route-handler-crud、実際の DB(SQLite / PostgreSQL 等)と接続する場合はこのパターン
  • Next.js 15 では params が Promise になるため await params が必要

注意点

nextjs-route-handler-crud はインメモリデータを使ったルートハンドラの CRUD パターン。これは Prisma を使った実際の DB 連携(schema.prisma 定義 → migrate → Client クエリ)。

関連サンプル

同じテーマや技術スタックを使った実装例

  • Next.js Route Handler で REST API(CRUD)を実装する

    app/api/ 配下の Route Handler を使い、GET / POST / PUT / DELETE を備えた REST API を実装する例。インメモリデータを使ってシンプルに CRUD を示す。

  • Prisma で論理削除(soft delete)を実装する

    deletedAt フィールドを使った論理削除パターンを Prisma で実装し、通常クエリから削除済みレコードを自動除外する例。

  • Prisma の orderBy で並び替えクエリを実装する

    Prisma の orderBy による単一フィールド・複数フィールド・リレーション先フィールドでの並び替えパターンと、null 値の扱い(nulls first / last)の例。

  • Prisma でフィルタ条件を動的に組み立ててクエリを実行する

    URL クエリパラメータから受け取った検索条件を Prisma の where 句に動的に組み立て、キーワード・カテゴリ・難易度などの複合フィルタクエリを実行するパターン。

  • Prisma で複数カラムをまたぐキーワード検索クエリを実装する

    タイトル・本文・タグなど複数カラムをまたぐキーワード検索を Prisma の OR 条件と fulltext 検索で実装するパターン。単語分割・スコアリングなしの実用的な部分一致パターンを示す。

関連仕様

このサンプルを理解するのに役立つ仕様や概念

  • FrameworkNext.jsReact ベースのフルスタックフレームワーク。SSR・SSG・App Router・API Routes を提供する。
  • API / OptionselectPrisma クエリで取得するフィールドを明示的に指定するオプション。不要なフィールドを除外してover-fetching を防ぐ。
  • API / OptionwherePrisma クエリで絞り込み条件を指定するオプション。完全一致・部分一致・複数条件(AND / OR)など様々なフィルタを組み立てられる。
←サンプル一覧に戻る