Skip to content

Next.jsとPrismaでデータベース操作#

Next.jsとPrismaでWebアプリケーションを作る4回目です。 最初からやりたい場合はナビゲーションから初回を開いてください。

ここでは、Next.jsアプリケーションでPrismaを使ってデータベースにデータを保存する方法を学びます。従来の構成ではTypeORMを使用していましたが、Next.jsプロジェクトではPrismaを使うのが一般的です。Prismaは型安全でモダンなORMツールで、Next.jsとの相性も抜群です。

データベースの準備#

まず、Podmanを使ってPostgreSQLデータベースを起動します。Podmanはこちらの手順でインストールしてください。

ターミナルでmynextappディレクトリに移動し、package.jsonに以下のスクリプトを追加します:

{
  "name": "mynextapp",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "start:db": "podman run -d --rm -p 5432:5432 -v postgres:/var/lib/postgresql/data -e POSTGRES_PASSWORD=postgres --name postgres postgres:15-alpine"
  },
  // ...残りの設定
}

そして、ターミナルで以下のコマンドを実行してデータベースを起動します:

npm run start:db

Prismaのセットアップ#

次に、Prismaをインストールして初期化します:

npm install prisma @prisma/client
npx prisma init

このコマンドを実行すると、.envファイルとprismaディレクトリが作成されます。.envファイルを開いて以下のように編集してください:

DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres?schema=public"

データモデルの定義#

prisma/schema.prismaファイルを開き、以下のようにアンケートのデータモデルを定義します:

generator client {
  provider = "prisma-client-js"
}

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

model Enquete {
  id      Int    @id @default(autoincrement())
  point   Int
  message String
  mail    String
}

定義したモデルでデータベースを初期化します:

npx prisma migrate dev --name init

このコマンドは、定義されたモデルに基づいてSQLマイグレーションファイルを生成し、それをデータベースに適用します。また、Prisma Clientも生成されます。

Prisma Clientの設定#

Prismaを使うためのクライアントを設定します。lib/prisma.tsというファイルを作成して以下のように実装します:

import { PrismaClient } from '@prisma/client'

// PrismaClientのグローバルインスタンスを防ぐための対策
const globalForPrisma = global as unknown as { prisma: PrismaClient }

export const prisma = globalForPrisma.prisma || new PrismaClient()

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

このコードは、開発中に自動リロードが発生した際に複数のPrismaClientインスタンスが作成されることを防ぎます。

アンケート送信APIの作成#

Next.jsのAPI Routesを使ってアンケートを保存するAPIを作成します。app/api/enquetes/route.tsというファイルを作成して以下のように実装します:

import { prisma } from '@/lib/prisma'
import { NextResponse } from 'next/server'

// アンケートデータの型定義
export interface EnqueteData {
  point: number
  message: string
  mail: string
}

export async function POST(request: Request) {
  try {
    const body: EnqueteData = await request.json()

    // バリデーション
    if (!body.point || !body.message || !body.mail) {
      return NextResponse.json(
        { error: '必須フィールドが不足しています' },
        { status: 400 }
      )
    }

    // データベースに保存
    const enquete = await prisma.enquete.create({
      data: {
        point: body.point,
        message: body.message,
        mail: body.mail
      }
    })

    return NextResponse.json(enquete)
  } catch (error) {
    console.error('アンケート保存エラー:', error)
    return NextResponse.json(
      { error: 'アンケートの保存に失敗しました' },
      { status: 500 }
    )
  }
}

// GETメソッドの実装(アンケート一覧取得用)
export async function GET() {
  try {
    const enquetes = await prisma.enquete.findMany()
    return NextResponse.json(enquetes)
  } catch (error) {
    console.error('アンケート取得エラー:', error)
    return NextResponse.json(
      { error: 'アンケートの取得に失敗しました' },
      { status: 500 }
    )
  }
}

このAPIは、POSTリクエストでアンケートデータを受け取って保存し、GETリクエストで保存されたアンケート一覧を返します。

アンケートIDでの個別取得API#

特定のアンケートを取得するためのAPIも作成します。app/api/enquetes/[id]/route.tsというファイルを作成します:

import { prisma } from '@/lib/prisma'
import { NextResponse } from 'next/server'

export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  try {
    const id = parseInt(params.id)

    if (isNaN(id)) {
      return NextResponse.json(
        { error: '無効なIDです' },
        { status: 400 }
      )
    }

    const enquete = await prisma.enquete.findUnique({
      where: { id }
    })

    if (!enquete) {
      return NextResponse.json(
        { error: 'アンケートが見つかりません' },
        { status: 404 }
      )
    }

    return NextResponse.json(enquete)
  } catch (error) {
    console.error('アンケート取得エラー:', error)
    return NextResponse.json(
      { error: 'アンケートの取得に失敗しました' },
      { status: 500 }
    )
  }
}

Prisma Studioでデータベースを視覚的に操作#

Prisma Studioは、データベースを視覚的に操作するためのWebインターフェースです。以下のコマンドで起動できます:

npx prisma studio

ブラウザが自動的に開き、http://localhost:5555 でPrisma Studioが表示されます。ここでデータベースのテーブルを確認したり、レコードを手動で追加・編集・削除したりできます。

Prisma Studio

Server Actionsでアンケートを保存#

API Routesだけでなく、Next.jsのServer Actionsを使ってアンケートを保存することもできます。app/actions/enquete.tsというファイルを作成します:

'use server';

import { prisma } from '@/lib/prisma';

export async function saveEnquete(formData: FormData) {
  try {
    const point = parseInt(formData.get('point') as string);
    const message = formData.get('message') as string;
    const mail = formData.get('mail') as string;

    // バリデーション
    if (!point || !message || !mail) {
      return {
        success: false,
        error: '必須フィールドが不足しています'
      };
    }

    // データベースに保存
    const enquete = await prisma.enquete.create({
      data: {
        point,
        message,
        mail
      }
    });

    return {
      success: true,
      enquete
    };
  } catch (error) {
    console.error('アンケート保存エラー:', error);
    return {
      success: false,
      error: 'アンケートの保存に失敗しました'
    };
  }
}

このServer Actionは、HTMLフォームから直接呼び出すことができます。

まとめ#

Prismaを使うことで、TypeORMと比較して以下のような利点があります:

  1. 型安全性: PrismaはTypeScriptと緊密に統合されているため、より型安全なコードを書けます
  2. 自動生成されるクライアント: スキーマ定義から自動的にクライアントが生成されます
  3. Prisma Studio: データベースを視覚的に操作できるツールが組み込まれています
  4. マイグレーション: データベーススキーマの変更を簡単に追跡・適用できます
  5. Next.jsとの統合: Server ComponentsやServer Actionsとシームレスに連携できます

Next.jsとPrismaを組み合わせることで、フルスタックアプリケーションの開発が非常にシンプルかつ効率的になります。

次は、Next.jsでマルチページアプリケーションを作成する方法を学びましょう。