🌻

PlanetScaleをNext.jsとPrismaで始める

2022/05/16に公開

PlanetScaleをNext.jsとPrismaで始める

なんだか話題になっているPlanetScaleですが,以前は,英語できない,DBわからない,Prisma未経験な状態で,モダンと聞いただけでPlanetScaleを始めようとしたけど,結局わからないことが多く,実用に踏み出せなかったのですが,レベルが18から24くらいに上がったことでちょっと理解できることが増えたので,改めて始め方と使い方をわかりやすくまとめて見ようと思います.

名目としては,フロントエンド,バックエンドでのAPI開発,データベースの操作一貫して開発することでゆとりフルスタックエンジニアになることです.

PlanetScaleでデータベースを作成する

PlanetScaleとは

公式サイトを見るからにすごそうなやつ(単純)

https://planetscale.com/

PlanetScaleは一言でいうと,本格的なSQLデータベースを簡単に使えるようにしてくれるいい奴.

これは私の勝手な解釈ですが,オープンソースであり,ビックネームの面子が揃っていることから察するに,「Webサービス作るときにみんなとりあえずAWSにSQLのDBをデプロイして使うよね!結構めんどくさいよね!みんなでこのめんどくさいの楽にできるやつ作ろうね!」ってノリで出来上がったすごいやつって感じです.

サーバレスデータベース(これはサーバを持たないわけでなく,従量制とかにしてくれる運用のコスパを考えたDBのこと)であり,ボタンポチポチでDBをサーバーにデプロイしてくれるので,フロントエンドの開発に注力できる点が利点.デプロイ先にはしっかり日本もあります.

また,DBごとにbranchという概念が存在し,branchごとにDBの中身を切り替えることができそう.(未検証)

登録する

まずは,アカウント登録を済まそう.

GitHubのアカウントで簡単に登録できる.(好きなものを使ってね★)

ちなみに無料では,Organizationを3つ,OrganizationごとにDBを1つとDBのbranchを3つまで作成できる.

順次説明していきます.

Organizationを作成する

まずはOrganizationを作成しましょう.無料プランでは3つまで作成可能.

Organizationを作るとこんな感じのおしゃれすぎて宇宙って感じの画面になると思います.

Databaseを作成する

理解をしてもしなくても,進むとこのようにDBを作るボタンが出てくるので,作りましょう.

出てこなくてもそれっぽいボタンを見つけてDBを作りましょう.

名前とRegion(日本にいる方ならTokyoでいいかと)を決めて作ります.

ちなみにpscale database create book-nobという記述がありますが,PlanetScaleではちょくちょく,「CLIではこのコマンドだよ!」みたいな表示をしてくれます.とても親切ですが,「次の手順はCLIでやるってこと?」ってならないように気をつけましょう.基本操作はCLI OnlyかGUI Only(ボタンポチポチ)で可能です.

また,CLIを使う場合はpscaleというものをPCインストールすることで使えます.MacであればHomebrewでインストールできます.

詳しくは公式のこちらをご参考ください.

https://planetscale.com/cli

Databaseに接続する準備をする

フロントエンドとDatabaseを接続するための準備をします.

作成したDBをクリックするとDBのメニュー画面みたいなものがでるので,Overviewから右のConnectを押しましょう.接続に必要な情報が記載してあります.

Connect with Prismaを選択し,.envschema.prismaの内容を確認し,後ほどSetupするNext.jsのアプリ内の各ファイルに反映させますので,必要な情報を控えておきましょう...(*)

Next.jsのSetup

今回はフロントエンドをNext.jsで構築します.(好きなものを使ってね★)

このフロントエンドのアプリとDBを接続して,データを操作するための準備をしていきます.

Next.jsに関する説明は省きます.

アプリを作成する

yarn create next-app --typescript

TypeScriptはお好みで

PrismaのSetup

Prismaとは

PrismaはTypeScriptに対応したORMです.
ORM(Object Relational Mapping)とはSQLを操作するの必要な言語に変換してくれるツールの総称で,JavaScriptを書くことでSQLの操作(本当はSQLを書かなければならない)を可能にしてくれるということです.
さらに,それだけではなく,PrismaはDBのschema(どんなデータが入るか)定義や型の自動生成もしてくれます.(他にもいろんなことができるのですが割愛します.)

公式はこちら

https://www.prisma.io/

Prisma関連の依存関係をinstall

今回はprismaを使ってDBと接続するので,以下の2つを入れましょう.

yarn add -D prisma
yarn add @prisma/client

prismaに関するファイルを作成/編集

必要なファイルを作ってくれる魔法を唱えましょう.

npx prisma init

prisma/schema.prismaが作成されるので,そこを(*)の内容に書き換えます.

generator client {
  provider = "prisma-client-js"
  previewFeatures = ["referentialIntegrity"]
}
datasource db {
  provider = "mysql"
  url = env("DATABASE_URL")
  referentialIntegrity = "prisma"
}

次の環境変数も(*)の内容で準備しましょう.

.envファイルを作成し,(*)の内容を貼り付けます.

DATABASE_URL='mysql://xxxxxxxx:pscale_pw_xxxxxxxxxxxxxxxxxx?sslaccept=strict'

また,この環境変数はGitに公開されないように.gitignoreファイルに.envを追加しておきましょう.

prisma/schema.prismaにDBスキーマを定義する

Prismaではこのファイルに指定したschema(スキーマ)でDBのテーブルを作ってくれ,型まで自動生成してくれます.

今回はこちらのコードをprisma/schema.prismaに追記してください.

model Book {
  id          Int    @id @default(autoincrement())
  title       String
  description String
  price       Int
  authorId    Int
  author      Author @relation(fields: [authorId], references: [id])
}

model Author {
  id    Int    @id @default(autoincrement())
  name  String
  books Book[]
}

これは本と著者をDBに保存するためのスキーマの例です.

  • Bookというオブジェクトはid,title,description,authorIdというプロパティを持ち,authorIdを参考にAuthorというオブジェクトと紐づいています.
  • books Book[]はAuthorオブジェクトが複数のBookと紐付かれることを示しています.
  • それぞれのオブジェクトのidは自動で連番で割り当てられます.

と言ったような意味を示すPrisma独自が開発したコードとなっています.VSCodeの拡張機能を入れると見やすくなり,エラーも教えてくれるので,入れておくといいでしょう.

今回はこちらでコードを用意しましたが,カスタマイズしたい場合の書き方のなどはこちらをご参考ください.

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

DBにテーブルを作成する

スキーマの定義が終わったら,PlanetScale側のDBにテーブルを作成します.

テーブルとは,保存されるデータの形のようなもので,DBに予め「ここにはこういうデータが入る予定だからよろしく!」と伝えるみたいな感じです.

prisma/schema.prismaの記述を終えたら,

npx prisma db push

とすることで,PlanetScaleのDBにPush(定義したスキーマをテーブルに反映)できます.

PlanetScale側で確認してみます.

DBのSchemaを選択し,SQLで書かれたテーブルっぽいものが表示されれば成功です!(表示されない場合はRefreshを押してみたら表示されるかもです.)

Prisma Studioでデータを作成する

Prisma StudioとはGUIで,DBの操作をすることができるツールでPrismaを使用する場合は標準で使用することができます.

npx prisma studio

と叩くとlocalhost:5555でPrisma Studioが起動します.

試しに著者を追加してみましょう.

いい感じです.ついでに本も追加してもいいでしょう.

データを取得する

先に簡単にデータを取得する工程を説明します.

front:フロントエンドから予め作成したバックエンドのAPIにRequestを送る
↓
back:フロントからRequestが来たらPrismaを使ってPlanetScaleで作成したDBに問い合わせる
↓
back:DBから取得したデータをResponseとしてフロントに返す
↓
front:DBから取得したデータがResponseとして返ってくる

こんな具合ですので,ざっくり把握しておくと,このあとの作業が何をしているのかわかると思います.

Next.jsのAPI Routesを使ってAPIを作成[backend]

Next.jsではNodeのランタイムで動かせるバックエンドのAPIを簡単に作成できます.わざわざバックエンドのアプリを作成せずに済むので.今回はこれを使います.

https://nextjs.org/docs/api-routes/introduction

pages/api/の中にファイルを作ることで簡単にバックエンドにAPIを作成することができます.
もともとあるpages/api/hello.tsをひな形にしつつ,以下のように書き換えます.

ファイル名はpages/api/authors/index.tsとしてください.

import { Author } from '@prisma/client';
import type { NextApiRequest, NextApiResponse } from 'next';

import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Author[]>,
) {
  /* 著者リストを取得 */
  const authors = await prisma.author.findMany();
  res.status(200).json(authors);
}

import { Author } from '@prisma/client';はPrismaが自動生成した型を使っています.

作成したAPIを叩いてデータを取得する[front]

pages/index.tsxに以下を追加してConsoleを確認しましょう.

useEffect(() => {
  fetch('/api/authors')
    .then((res) => res.json())
    .then(console.log);
}, []);

保存した著者のデータが取れているはずです.

データを保存する

続いては保存です.取得と同様にAPIを作成しますが,REST APIの原則に基づくとエンドポイントが両方とも/api/authorsとなってしまうので,それぞれにmethodを割り当てることで,処理を取得と保存に分岐するようにします.

pages/api/authors/index.tsを変更

import { Author } from '@prisma/client';
import type { NextApiRequest, NextApiResponse } from 'next';

import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Author[] | Author>,
) {
  const { method } = req;

  switch (method) {
    case 'GET':
      const authors = await prisma.author.findMany();
      res.status(200).json(authors);
      break;

    case 'POST':
      const author = await prisma.author.create({
        data: {
          name: 'King nob',
        },
      });
      res.status(200).json(author); // idを含む保存したデータを返す
      break;

    default:
      res.setHeader('Allow', ['GET', 'POST']);
      res.status(405).end(`Method ${method} Not Allowed`);
  }
}

今度はボタンが押されたらデータが保存されるようにしてみます.

pages/index.tsx

const handleClick = async () => {
  await fetch('/api/books', {
    method: 'POST',
  });
};

とjsx内に

<button onClick={handleClick}>post</button>

を追加

シンプルなアプリのサンプル

https://github.com/prog-learning/lesson-planetscale

DBの運用branchを分けることも

branchというとGitを思いかべるかもしれませんが,DBにも運用branchの概念があり,PlanetScaleでは,無料で3つまで作成できます.productionとして指定するとmainブランチのDBは直接操作できなくなります.(ありがたい)

Promote to production branchを押す

この先の操作説明は長くなりそうなので今回はしません!

説明はここ記載されているようです.

https://docs.planetscale.com/concepts/branching

まとめ

というわけで今回はMySQLのサーバレスデータベースをクラウド上にデプロイして簡単に使えるようにしてくれるPlanetScaleを使いDBサーバーを作成し,それをNext.jsとPrismaを使って読み書きができるようにしてみました.

かなり簡単な操作で,

フロントエンドからAPIリクエストを叩く
↓
APIリクエストを受けたバックエンドでデータベースと通信する処理を実行
↓
データベースへ必要に応じた操作
↓
バックエンドからフロントエンドにレスポンスを返す

という一般的なWebアプリの動作を実装することができました!

フロントエンドから学習を始めた私にとって未知だったバックエンドやデータベースが何なのかをかなり浅くですが,全体感を掴むことができました.

また,さらっと実装してしまいましたが,簡単にバックエンドで関数を実行できるNext.jsのAPI RoutesはバックエンドにおけるAPI開発の入門としては最適だと思いました.

宣伝

最後にこれらの技術を使って一つのWebアプリを作ってみる企画をやっていますので,よろしければ応援お願いします🙏

https://zenn.dev/nbr41to/books/dccb2a75582bff

Discussion