😎

Next.js(App Router) x PlanetScale x Prisma でプロジェクトを構築

2023/06/06に公開

はじめに

  • Next.js(App Router)、PlanetScale、Prisima でプロジェクトを構築する方法を紹介します。
  • PlanetScale でアカウントを作成し、実際にデータベースを作成します。
  • Prisma を通して、テーブルを作成、データを投入します。
  • Next.js の App Router を使って、データベースのデータを取得、表示します。
  • 本記事で作成したソースコードは以下にあります。

https://github.com/hayato94087/nextjs-planetscale-prisma

PlanetScaleについて

PlanetScale とは、クラウドネイティブな MySQL データベースです。シームレスなスケーリング、高可用性、セキュリティを備えています。裏側としては、Vitessというオープンソースのデータベースが採用されています。

PlanetScale の特出すべき特徴は以下の2点です。

  • MySQL を利用したサーバレスな DB
  • ブランチ機能によるデータベースのバージョン管理

特にブランチ機能は PlanetScale ならではの強みで、商用 DB から、開発 DB を作成できます。開発 DB でのテストが終わったら、ブランチをマージすることで、本番 DB に反映させることができます。本記事でも取り上げています。

https://planetscale.com/

Prismaについて

Prisma は Node.js と TypeScript 用のオープンソース ORM です。ORM とは、SQL を書かずに、データベースを操作するためのライブラリです。

https://www.prisma.io/

Prisma は、型安全なデータベースアクセスが特徴です。TypeScript との相性が良いです。

Prisma は以下の 3 つのモジュールを提供します。

  • Prisma Client
    • プログラムからデータベースを操作するためのクライアントライブラリ
  • Prisma Migrate
    • データベースのマイグレーションを実現するためのツール
  • Prisma Studio
    • データベースをそうさするための GUI ツール

以下のようなデータベースをサポートしています。

  • PostgreSQL
  • MySQL
  • SQLite
  • MongoDB
  • etc...

それでは、実際のプロジェクトを作成しながら、PlanetScale と Prisma の使い方を紹介していきます。

新規にNext.js プロジェクトを作成

プロジェクトを新規に作成します。今回は、next-app@latest を利用し、最新のバージョンをりようします。また、App Router を利用するため、--app を指定しています。

$ pnpm create next-app@latest nextjs-planetscale-prisma --typescript --eslint --import-alias "@/*" --src-dir --use-pnpm --tailwind --app

プロジェクトに移動します。

$ cd nextjs-planetscale-prisma

環境変数ファイルを作成

.env の空ファイルを作成します。これは後ほど利用します。

$ touch .env

.gitignoreを修正

以下を追加し、.env を Git の管理対象から外します。

.gitignore
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local
+.env

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

Prismaをインストール

Prisma CLI を devDependencies としてインストールします。

$ pnpm add -D prisma

Prismaの設定ファイルを作成

Prisma を Prisma CLI の init コマンドで初期化します。

$ npx prisma init
実行ログ(英語)
✔ Your Prisma schema was created at prisma/schema.prisma
  You can now open it in your favorite editor.

warn You already have a .gitignore file. Don't forget to add `.env` in it to not commit any private information.

Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver, mongodb or cockroachdb.
3. Run prisma db pull to turn your database schema into a Prisma schema.
4. Run prisma generate to generate the Prisma Client. You can then start querying your database.

More information in our documentation:
https://pris.ly/d/getting-started
実行ログ(英語)
✔ あなたのPrismaスキーマはprisma/schema.prismaで作成されました。
 お気に入りのエディタでそれを開くことができます。

注意 すでに.gitignoreファイルが存在します。.envを追加して、プライベートな情報をコミットしないようにしてください。

次のステップ:

1. 環境変数のDATABASE_URLを.envファイル二設定してください。DATABASE_URLは既存のデータベースへの接続情報です。まだテーブルが存在しない場合は、https://pris.ly/d/getting-started を読んでください。
2. 「schema.prisma」ファイルの「datasource」ブロックにあるプロバイダをあたなのデータベースにあわせて設定してください。(例:postgresql、mysql、sqlite、sqlserver、mongodb、またはcockroachdb)
3. 「prisma db pull」コマンドを実行し、データベーススキーマをPrismaスキーマに変換してください。
4. 「prisma generate」コマンドを実行し、Prismaクライアントを生成してください。その後、データベースへのクエリを開始できます。

詳細な情報は、以下のドキュメントを参照してください:
https://pris.ly/d/getting-started

実行後にファイルが2つ生成されます。

  • 1つ目が Prisma の設定ファイル(prisma/schema.prisma)です。
  • 2つ目が .env ファイルです。.env ファイルが無ければ新規に作成されます。.env ファイルにはデータベースへの接続情報を後ほど記入します。

自動生成された Prisma の設定ファイル(prisma/schema.prisma)です。

prisma/schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

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

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

自動生成された、.env ファイルです。

.env
# This was inserted by `prisma init`:
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"

それでは、つづいて、PlanetScale の設定します。

PlanetScaleのアカウントを作成

PlanetScale のアカウントを作成します。アカウントは手持ちの GitHub アカウントで簡単に作成できます。

サイトにアクセスします。

https://planetscale.com/

「Get started」をクリックします。

「Continue with GitHub」をクリックします。

自身が持っている GitHub アカウントでログインします。

「Authorize planetscale」をクリックします。

「Accept Terms of Service」をクリックします。

この画面に到達すると、自身のメールアドレスに確認メールが届いていますので、メールボックスを確認します。

「Confirm email」をクリックし、アカウント作成を完了させます。

アカウント作成が完了しました。

PlanetScaleでデータベースを作成

続いて、データベースを作成していきます。

初めにチュートリアルが表示されるので、ボタンをクリックして次へ進めていきます。

これでチュートリアル完了です。「Create your first database」をクリックして、データベースを作成します。

  • Name にはデータベース名を記入します。
  • Regionap-northeast-1(Tokyo) を選択します。これで、日本リージョンにデータベースを作成できます。
  • 最後に、「Create database」をクリックします。

「Initializing」と表示されているので、しばらく待ちます。

初期化が完了しました。

PlanetScaleでデータベースの接続先を取得

作成したデータベースへの接続先の情報を取得し、.env に設定します。

「Get connection strings」をクリックします。

「Craete password」をクリックします。

  • 接続先の情報が表示されました。
  • 「Connection with」から「Prisma」を選択肢、Prisma の設定を表示できます。
  • 「.env」に記入する環境変数が表示されています。環境変数に「DATABASE_URL」をコピーします。

Next.js の環境変数ファイルにペーストします。

.env
DATABASE_URL='mysql://hfgoc4ilkyvziou170iu:pscale_pw_x6gHc5eEPDOCnCHgWCR9tglpAMpLNMQLbL2Mwv9OlO6@aws.connect.psdb.cloud/nextjs-planetscale-prisma?sslaccept=strict'

環境変数としてデータベースへの接続先情報を設定しました。

PlanetScaleでPrismaの設定を取得

ブラウザに戻り「schema.prisma」を表示させます。
ここには、Prisma の設定が記述されています。こちらも後ほど必要になります。

Next.js のプロジェクトの Prisma の設定ファイル(schema.prisma)にペーストします。

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

datasource db {
  provider = "mysql"
  url = env("DATABASE_URL")
  relationMode = "prisma"
}

Prisma の設定を反映できました。

Prisma Clientをインストールします。

Prisma Client をインストールします。

$ pnpm add @prisma/client

prisma.schemaを編集します。

以下の Prisma のクイックスタートを参考にスキーマを修正します。

https://www.prisma.io/docs/getting-started/quickstart

今回は、User テーブル、Post テーブルを定義します。

prisma/schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

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

datasource db {
  provider = "mysql"
  url = env("DATABASE_URL")
  relationMode = "prisma"
}

+model User {
+  id    Int     @id @default(autoincrement())
+  email String  @unique
+  name  String?
+  posts Post[]
+}
+
+model Post {
+  id        Int     @id @default(autoincrement())
+  title     String
+  content   String?
+  published Boolean @default(false)
+  author    User    @relation(fields: [authorId], references: [id])
+  authorId  Int
+
+  @@index([authorId])
+}

DBにテーブルを作成する

スキーマ定義が完了したら、prisma db push コマンドを実行し、PlanetScale の DB にテーブルを作成します。User テーブル、Post テーブルが作成されます。

$ npx prisma db push
実行結果のログ
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": MySQL database "nextjs-planetscale-prisma" at "aws.connect.psdb.cloud"

🚀  Your database is now in sync with your Prisma schema. Done in 528ms

✔ Generated Prisma Client (4.15.0 | library) to ./node_modules/.pnpm/@prisma+client@4.15.0_prisma@4.15.0/node_modules/@prisma/client in 72ms

PlanetScale のコンソールに戻り、テーブルが作成されていることを確認します。

Table の数が 0 から 2 に変更されています。「Tables」をクリックします。

するとテーブルの一覧が確認できました。テーブルの定義も確認できます。

PostUser の2つのテーブルが作成されていることが確認できました。

Prisma Studioでデータを作成

Prisma Studio を利用して、データを作成します。Prisma Studio とは、Prisma の GUI ツールです。

以下のコマンドを実行すると、ブラウザが起動し、http://localhost:5555/ で Prisma Studio が表示されます。

$ npx prisma studio

「User」をクリックし、User テーブルのレコードを確認します。

現状は空のため何も表示されません。「Add record」を追加し、データを作成します。

2 件レコードを入力しました。「Save 2 changes」をクリックし、データを保存します。

登録が完了しました。idprisma.schemaautoincrement() を設定しているため、自動的にインクリメントされた値が登録されていきます。

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

続いて、Post テーブルにもデータを登録します。「Add record」を追加します。

データを入力します。先程作成した User と関連付けるため、「User」をクリックします。

関連付けたい User を選択します。

「Save 1 change」をクリックして、データを登録します。

データの登録が完了しました。

以上で、PrismaStudio を利用したデータの登録は完了です。

PlanetScaleでデータを確認する

先程登録したデータが PlanetScale のコンソールで確認できることを確認します。

「Console」をクリックします。

「Connect」をクリックします。

エディターが表示されるので SQL を入力します。

SQL 説明
select * from User Userテーブルのすべてのデータを表示します。
select * from Post Postテーブルのすべてのデータを表示します。

データが表示されました。

Next.jsでデータを取得

Next.js から Prisma に接続するためのクライアントを prismaClient.ts に作成します。

$ mkdir -p src/lib
$ touch src/lib/prismaClient.ts
lib/prismaClient.ts
import { PrismaClient } from '@prisma/client';

export * from '@prisma/client';

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

export const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    log:
      process.env.NODE_ENV === 'development'
        ? ['query', 'error', 'warn']
        : ['error'],
  });

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

データベースに接続し、UserPost のデータを取得し結果を表示するページを作成します。処理はサーバサイドで実行されます。注目すべきポイントはコメントとして記述しています。

$ mkdir -p src/app/select
$ touch src/app/select/page.tsx
src/app/select/page.tsx
// データベースに接続するためのクライアントをインポート
import { prisma } from "@/lib/prismaClient";

export default async function Home() {
  // Userテーブルから全てデータを取得
  const users = prisma.user.findMany();
  // Postテーブルから全てデータを取得
  const posts = prisma.post.findMany();

  return (
    <>
      <h1 className="font-bold text-2xl">Users</h1>
      {/* Userテーブルの結果の一覧を画面に出力する */}
      {(await users).map((user, index) => (
        <div key={user.id} className="bg-gray-800 m-2 w-[300px]">
          <p>id: {user.id}</p>
          <p>name: {user.name}</p>
          <p>email: {user.email}</p>
          {/* Add more user attributes as needed */}
        </div>
      ))}
      <br/>
      <h1 className="font-bold text-2xl">Post</h1>
      {/* Postテーブルの結果の一覧を画面に出力する */}
      {(await posts).map((post, index) => (
        <div key={post.id} className="bg-gray-800 m-2 w-[300px]">
          <p>id: {post.id}</p>
          <p>name: {post.title}</p>
          <p>content: {post.content}</p>
          <p>published: {post.published+``}</p>
          <p>authorId: {post.authorId}</p>
        </div>
      ))}
    </>
  );
}

今回は findMany を利用していますが、Prisma では様々な API が用意されています。詳細は以下のリンクを参照してください。

https://www.prisma.io/docs/reference/api-reference/prisma-client-reference

実行します。

$ pnpm dev

http://localhost:3000/select にアクセスすると、以下のようにデータが表示されます。

PlanetScaleでデータを手動でバックアップする

PlanetScale ではデータベースのデータをバックアップできます。バックアップは手動で行うこともできますが、定期的に自動でバックアップを行うこともできます。バックアップについては公式サイトに記載されています。

https://planetscale.com/docs/concepts/back-up-and-restore

まず、手動バックアップの方法です。

「Backups」にアクセスし、「Create new backup」をクリックします。

  • 「Branch」を指定します。
  • 「Name」は適当に入力します。
  • どの程度の期間バックアップを保持するかを指定します。
  • 「Create backup」をクリックします。

バックアップの作成が完了しました。バックアップの作成には数分かかります。

PlanetScaleでデータを定期的にバックアップする

スケジュールを登録し、定期的にバックアップをする設定をします。

「Backups」にアクセスし、「Add new schedule」をクリックします。

  • 実行する頻度、タイミングを指定します。(今回は毎日、10:47 に実行するように設定しています)
  • どの程度の期間バックアップを保持するかを指定します。(今回は、1 ヶ月間保存するように設定しています。)
  • 任意で名前を指定します。
  • 最後に、「Save schedule」をクリックします。

デイリーでバックアップが作成されるように設定されました。

PlanetScale でデータを定期的にバックアップする設定は以上です。

PlanetScaleでモニタリング

Insight でクエリの実行結果のログとパフォーマンスを可視化できます。以下の公式サイトで記述されています。

https://planetscale.com/docs/concepts/query-insights

Insights のページを開きます。

グラフエリアでは、以下の種類のグラフを選択できます。

グラフ 説明
Query latency クエリの実行時間
Queries per second 秒間のクエリ数
Rows read per second 秒間の読み込み行数
Rows written per second 秒間の書き込み行数
Query errors クエリのエラー数

実行されたクエリの一覧を確認できます。エラーのクエリに絞って見ることもできます。

PlanetScaleで開発ブラントを作成する

PlanetScale では目的にあわせて、DB をブランチとして管理できます。ブランチについては以下の公式サイトで記述されています。

https://planetscale.com/docs/onboarding/branching-and-deploy-requests#what-are-branches

まず、開発用ブランチを作成します。「New branch」をクリックします。

  • 「Name」にブランチ名を記載します。
  • 「Create branch」をクリックしてブランチを作成します

「dev」ブランチが作成できました。

PlanetScaleで商用ブラントを作成する

次に、「main」ブランチを商用ブランチにプロモートします。「main」をクリックします。

「Promote to production」をクリックして、商用ブランチにプロモートします。

商用ブランチにプロモートできました。

ブランチの全体像です。

  • main が商用ブランチです。
  • dev が開発ブランチです。

まとめ

  • Next.js(App Router)、PlanetScale、Prisima でプロジェクトを構築する方法を紹介しました。
  • PlanetScale でアカウントを作成し、実際にデータベースを作成しました。
  • Prisma を通して、テーブルを作成、データ投入しました。
  • Next.js の App Router を使って、データベースのデータを取得、表示しました。

Prisma もいいですが、最近話題の Drizzle を今度は使ってみたいです。

Discussion