Next.js に PostgreSQL バックエンドをつなぐ

힘센캥거루
2025년 7월 16일(수정됨)
63
nextjs

バックエンドを簡単に実装して会員登録までは作っておいたのだが、不思議なことにその先にはなかなか手が伸びなかった。

おそらく Prisma と PostgreSQL を触ってはいたものの、誰かの記事を読みながら受動的に作業しただけで、きちんと身についていなかったのが問題だと思った。

そこで実際に自分で一度実装してみることにした。

1. PostgreSQL をインストールする

まず homebrew で postgresql をインストールする。

Windows の場合は choco をインストールして使えば簡単にできる。

そして services start で自動起動するようにしておく。

# Mac の場合
brew install postgresql
brew services start postgresql

下記のコマンドを入力して正常に接続できればインストール完了。

PostgreSQL はサーバー・クライアント構造なので、Postgre サーバーが起動していないと DB に接続できない。

psql postgres
Next.js に PostgreSQL バックエンドをつなぐ-1

ではユーザーと DB を設定しよう。

ユーザー名は testuser、パスワードも testuser に設定した。

CREATE USER testuser WITH PASSWORD 'testuser';
\du
Next.js に PostgreSQL バックエンドをつなぐ-2

なかなかユーザーが作成されず確認してみたところ、最後にセミコロンを必ず付けないとコマンドが終わらないのだった。

続いて database も 1 つ作成しよう。

CREATE DATABASE testdb;

そして \l\list でデータベースを確認する。

Next.js に PostgreSQL バックエンドをつなぐ-3

ここで上の方にある 3 つの DB はデフォルトで作成されるものだ。

削除すると問題になる可能性があるので、そのまま残しておく方がよい。

2. Prisma をインストール

次に Prisma をインストールする。

自分は prismaTest というフォルダを 1 つ作成した。

npm を使ってもいいが、自分はそのまま yarn で初期化した。

yarn

そして Prisma をインストールする。

npx コマンドで Prisma の初期設定を作成する。

prisma init を実行すると 1 つのフォルダ内に Prisma の設定ファイルが生成される。

ちなみに npx は npm パッケージをインストールせずに実行できるコマンドツールだ。

yarn add prisma
npx prisma init

3. PostgreSQL 接続設定

次に prisma/schema.prisma.env に移動して環境設定を修正する。

ファイル内で以下のように設定を変更すればよい。

DATABASE_URL="postgresql://アイディ:ビ밀번호@localhost:5432/데이터베이스이름?schema=public"

4. schema.prisma 設定

ここでデータベースのスキーマを設定する。

デフォルトでは下記のようなスキーマが入っている。

generator client {
  provider = "prisma-client-js"
  output   = "../generated/prisma" <-- 이 줄 삭제할 것!
}

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

これを自由に変更すればよい。

問題はスキーマの書き方を少し覚えなければならないということ。

例えば次のようなスキーマがあるとしよう。

model User {
  id    Int @id @default(autoincrement())
  email String  @unique
  name  String?
}

➡️ model User { ... } はデータベースのテーブル名。

➡️ id Int @id @default(autoincrement())

  • このフィールドは主キーで、数値が 1, 2, 3… と自動で埋められる。

要素

意味

id

フィールド(列、カラム)名

Int

データ型 = 整数型

@id

このフィールドはPrimary Key である

@default(autoincrement())

デフォルト値は自動増分の数値

➡️ email String @unique

  • email の値は一意でなければならず、同じメールアドレスを持つユーザーが 2 人以上存在してはならない。

要素

意味

email

フィールド名

String

文字列型

@unique

重複不可(Unique 制約)

➡️ name String?

  • name はあってもいいし、null(なくても)でもよい。

    要素

    意味

    name

    フィールド名

    String?

    文字列型で、?nullable(null 許容) を意味する

つまり Prisma のデコレーターを整理すると次のようになる。

デコレーター

意味

@id

主キー指定

@default(...)

デフォルト値設定

@unique

ユニーク制約

@relation(...)

リレーション設定(外部キー、関連テーブル)

@map("db_column")

実際の DB 上でのカラム名を指定

?

そのフィールドは nullable(値がないこともありうる)

[]

配列(例: String[] = 文字列配列)

@필드명

フィールドの型が datetime のとき、データ修正時に現在日時へ自動更新

5. マイグレーション実行

DB にモデルを反映させるため、マイグレーションを行う。

最後の名前は自由に決めてよい。

npx prisma migrate dev --name testMyDB
## --name の後ろにマイグレーション名を入力

6. Prisma Client 使用例

ここで簡単なサーバーを作ってバックエンドでの CRUD をテストしてみよう。

サーバーは Express で作成する。

yarn add @prisma/client express

まずは上記のコマンドでインストールする。

index.js ファイルを作成し、次のように入力する。

そしてターミナルで node index.js を実行するとサーバーが起動する。

const express = require('express');
const { PrismaClient } = require('@prisma/client');

const app = express();
const prisma = new PrismaClient();

app.use(express.json());
const port = 3001;

app.get("/", (req, res)=> {
   const body = req.params;
   res.send("test");
});

app.get('/users', async (req, res) => {
  const users = await prisma.User.findMany();
  console.log(users);
  res.send(`<div>${users.map((user) => {
    return `<name:$>email : ${user.email} / name:${user.name}</p><br>`
  }).join("")}</div>`);
});

app.get('/input', async (req, res) => {
  const { email, name } = req.query;
  const result = await prisma.User.create({data:{email : email, name: name}})
  console.log(email, name);
  res.send(`<h1>${email
  }</h1>
  <h2>${name}</h2>
  `);
})

app.listen(port, () => {
    console.log("listen http://localhost:3001")
});

Prisma は prisma.テーブル名.メソッド という形式で動作する。

サーバーが動いているので、クエリストリングでメールアドレスと名前を入力してみる。

http://localhost:3001/input?email=testur@email.com&name=힘센캥거루

を入力したあと /users で確認してみると、データがちゃんと出力されているのが分かる。

Next.js に PostgreSQL バックエンドをつなぐ-4

同じ要領で更新・削除も可能だ。

下記のコードを追加してみよう。

...
app.get("/delete", async (req, res) => {
  const { email } = req.query;
  const result = await prisma.User.delete({where : {email: email}});
  console.log(email);
  res.send(`<h1>${email} 삭제 성공</h1>`)
})
...

そして下のような URL でリクエストすると削除される。

http://localhost:3001/delete?email=testur@email.com

更新も難しくない。

where で条件を指定し、data フィールドで内容を変更すればよい。

...
app.get("/edit", async (req, res) => {
  const { email, name } = req.query;
  const result = await prisma.User.update({where : {email: email}, 
    data : {name : name}
  });
  console.log(email, name);
  res.send(`<h1>${email} 이름 수정 성공</h1>`)
})
...

そしてクエリストリングを付けてリクエストしたあと確認すると、下のように名前が変更されていることが分かる。

Next.js に PostgreSQL バックエンドをつなぐ-5

7. Next.js で使う

Next.js で Prisma を簡単に使うには、事前の準備が必要だ。

自分は src/lib フォルダ内に prisma.ts ファイルを作成した。

user に関するすべての入出力を担当するコードを書く。

import { PrismaClient } from "@prisma/client";

const globalWithPrisma = global as typeof globalThis & {
  prisma: PrismaClient;
};

let prisma: PrismaClient;

// 本番モードのときは毎回新しい接続を作成
if (process.env.NODE_ENV === "production") {
  prisma = new PrismaClient();
} else {
  if (!globalWithPrisma.prisma) {
    globalWithPrisma.prisma = new PrismaClient();
  }
    // 開発モードのときはメモリリーク防止のため既存の接続を使用
  prisma = globalWithPrisma.prisma;
}

export default prisma;

このようにしたあと、/src/db 内では user を管理するための関数を定義した。

import { dbUserObject } from "@/types/allTypes";
import prisma from "@/lib/prisma";

export async function createUser(data: dbUserObject) {
    try {
        const user = await prisma.user.create({
            data: {
                ...
                email : data.user.email as string,
                ...
            }
        });
    
        return user; // 生成されたユーザーを返す
    } catch (error) {
        console.error('Error create user', error);
        throw error;
    }
}

export async function getAllUsers() {
    try {
      const users = await prisma.user.findMany();
      return users;
    } catch (error) {
      console.error('Error fetching users:', error);
      throw error;
    }
  }

  // Read - 特定ユーザーの取得
export async function getUserByEmail(email: string) {
    try {
      const user = await prisma.user.findUnique({
        where: { email },
      });
      return user;
    } catch (error) {
      console.error('Error fetching user:', error);
      throw error;
    }
  }

  export async function updateUser(email: string, data: Partial<Omit<dbUserObject, 'email'>>) {
    try {
      const updatedUser = await prisma.user.update({
        where: { email },
        data: {
          nickName : data.user?.nickName,
          ...
        },
      });
      return updatedUser;
    } catch (error) {
      console.error('Error updating user:', error);
      throw error;
    }
  }

  export async function deleteUser(email: string) {
    try {
      const deletedUser = await prisma.user.delete({
        where: { email },
      });
      return deletedUser;
    } catch (error) {
      console.error('Error deleting user:', error);
      throw error;
    }
  }

8. 感想

バックエンド自体を難しく考えていたが、助けてくれるツールがあるとずっと簡単だった。

いろいろなライブラリがあるが、その中でも Prisma が一番直感的で良い気がする。

これからはこれを使って自分のホームページやプロジェクトも一度作ってみたい。

댓글을 불러오는 중...