Prismaの導入とメリットを考える

# はじめに
Node.js + TypeScriptによるサーバーサイドの開発は、クライアントサイドとスクリプトを同じ言語で管理できるなどのメリットがあります。
その際に使用するのが、Node.jsウェブフレームワークであり、データベース連携は必要不可欠です。
ですが、普段データベースに触れる機会が少ないデータベース初心者にとって、SQL文を書くのはハードルが高く感じます。

そういった状況で役に立つのが、「Object-Relational Mapping / オープンソースのオブジェクト関係マッピング」(以降ORM)です。
「[Prisma](https://www.prisma.io/)」はNode.js ORMの1つです。
本記事では、Prismaについての理解を深めることを目的とします。

## 前提と対象読者
以下の知識や経験があり、
- Node.jsの基礎知識
- Node.jsウェブフレームワークの使用経験

以下の考えをお持ちの方。
- Node.jsによるORMに興味がある
- フロントエンドもバックエンドも同じ言語(JavaScript / TypeScript)で実装したい
- 型安全な開発がしたい
- データベースには不慣れだが手軽にAPIを実装したい

## 本記事の目的とゴール
- Prismaの機能や使い方に関する紹介
- ORMの概要について説明できるようになる
- Prismaの概要について説明できるようになる
- Prismaを利用するための初期設定ができるようになる
- Prismaを利用してデータベースへのアクセスに必要な記述をできるようになる

# ORMとは
ORMについては、[オブジェクト関係マッピング - Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E9%96%A2%E4%BF%82%E3%83%9E%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0)にて以下の説明がされています。
> オブジェクト関係マッピング（英: Object-relational mapping、O/RM、ORM）とは、データベースとオブジェクト指向プログラミング言語の間の非互換なデータを変換するプログラミング技法である。オブジェクト関連マッピングとも呼ぶ。実際には、オブジェクト指向言語から使える「仮想」オブジェクトデータベースを構築する手法である。

簡単に言うと、**プログラミング言語のオブジェクトで定義したメソッドで、SQLを書かずにデータベースの操作が可能なツール**ということです。
データベースの操作や管理を仲介する役割を持っています。  
また、データベースの作成やマイグレーションといった操作も可能です。

## なぜNode.jsにてORMを利用するのか
Node.jsには、リレーショナルデータベースに対する統一的なインターフェースが存在しません。
リレーショナルデータベースにアクセスするためには、npmパッケージを利用します。
アクセス方法は各データベースにより異なります。
さらに以下の点を考慮する必要があります。

- 各データベースごとに公式・非公式問わずnpmパッケージが複数存在する
- 各データベースのnpmパッケージは開発・保守が止まっているものもある

以上のことから、npmパッケージの選定を慎重に行わなければなりません。
そこでORMを利用します。
ORMを利用することにより、各データベース<sup>※</sup>へのアクセスを一律に担ってくれます。
さらに、先述したとおりSQLを書かずにオブジェクトで定義されたメソッドでデータベースの操作が可能になります。そのため、JavaScriptもしくはTypeScriptで記述することができます。

※ [mongoose](https://mongoosejs.com/)のように1つのデータベースを対象にしたORMも存在します。

# Prisma概要
Prismaは、[公式](https://www.prisma.io/)にて以下の宣言をしています。
>Prisma unlocks a new level of developer experience when working with databases thanks to its intuitive data model, automated migrations, type-safety & auto-completion.
>
>Prismaは、直感的なデータモデル、自動マイグレーション、型安全性、自動補完機能により、データベースを使用する際の新しいレベルの開発者体験を提供します。

PrismaはNode.jsを対象としたオープンソースORMです。
型安全なデータベースアクセスが特徴で、TypeScriptとの相性が良いです。
Prismaを構成するモジュールは以下の3つです。
- Prisma Client
- Prisma Migrate
- Prisma Studio

## Prisma Client
Node.js, TypeScriptのための、データに合わせて自動生成される型安全なクエリビルダー。
メソッドでデータベースを操作するための機能です。

## Prisma Migrate
マイグレーションシステム。設定ファイル（schema.prisma）に基づき実行されます。

## Prisma Client
データベースを操作するためのGUIツールです。

## データベース・フレームワーク・ライブラリとの連携
下記のとおり、様々なデータベース・フレームワーク・ライブラリと連携が可能です。

### データベース
- PostgreSQL
- MySQL
- SQLite
- MongoDB
- etc...

### フレームワーク・ライブラリ
- Next.js
- Nest.js
- Apollo
- GraphQL
- Express
- Fastify
- etc...

## 他ORMとの比較
[Sequelize](https://sequelize.org/)や[TypeORM](https://typeorm.io/)が同じNode.jsのORMとして比較されることが多いです。
以下の図は過去1年のダウンロード数の比較です。
![過去1年のダウンロード数](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584922/3a9271c8-64b4-68d4-39f0-9bdc441b5a62.png)
出典：[npm trends](https://npmtrends.com/prisma-vs-sequelize-vs-typeorm)
詳細な比較は以下を参照ください。
- [Comparing Prisma / Sequelize](https://www.prisma.io/docs/concepts/more/comparisons/prisma-and-sequelize)
- [Comparing Prisma / TypeORM](https://www.prisma.io/docs/concepts/more/comparisons/prisma-and-typeorm)

下記は、以前Sequelizeを使用した際に不便を感じた点です。
- Sequlize + TypeScriptの組み合わせで実装すると、TypeScript対応のための追加モジュールが必要になり、記述も冗長になる
- データ取得の際の条件指定も専用の比較演算子を使用する必要があり、慣れが必要

Prismaは上記の問題がありませんでした。
特に、TypeScriptを使用する際に特別な設定・記述をする必要がなく、強力な型サポートを受けることができます。

# Prismaの導入と利用方法
今回はReact・Express・MySQL・Prismaの構成<sup>※1</sup>でCRUD操作ができる簡易的な書籍アプリ<sup>※2</sup>を作成したので、こちらを例に説明します。
![画面キャプチャ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584922/46416e06-dd7e-4eb0-48c2-91ea9632ce04.png)

※1 React、Express、MySQLのインストールや詳細設定については省略します。
※2 参考：[React / Express で作る Web アプリケーション開発入門](https://www.seplus.jp/dokushuzemi/blog/2021/12/tutorial_react_express.html)

手順は以下のとおりです。
1. Prismaのインストール
2. schema.prismaの設定
3. マイグレーション
4. APIの実装(Express)
5. Prisma studioの起動

## prismaのインストール
以下のコマンドを実行します。
```
yarn add @prisma/client
```
## schema.prismaの設定
Prismaをインストールするとprismaディレクトリ内にschema.prismaが作成されます。
schema.prismaに必要な設定を追加します。
```
generator client {
  provider = “prisma-client-js”
}
datasource db {
  provider = “mysql”
  url      = env(“DATABASE_URL”)
}
model books {
  id Int @id @default(autoincrement())
  title String
  author String
  overview String
  created_at DateTime @default(now())
  updated_at DateTime @default(now())
}
```
- generator clientはprisma generateコマンドの対象を設定する
    - ファイルの内容を更新してマイグレーションをした際に実行される
- datasource dbは使用するデータベースの情報を設定する
    - urlは環境変数を使用
- model booksはデータモデルを設定する。modelの後にテーブル名を指定し、フィールド・データタイプ、オプションを設定
    - @defaultはデフォルト値を設定可能

## マイグレーション
以下のコマンドを実行します。
```
npx prisma migrate dev --name init
```
マイグレーションが完了したら、APIを実装しPrisma Clientを通じてデータベースにアクセスできるようにします。

## APIの実装(Express)
Expressのルーティングにエンドポイントを追加します。
PrismaClientをインスタンス化して使用し、各クエリを発行します。
クエリの結果はすべて完全に型付けされます(ここが素晴らしい！)。

```typescript
const { PrismaClient } = require(“@prisma/client”);
const express = require(“express”);
const router = express.Router();
router.get(“/”, async (_req:Request, res:Response, _next:NextFunction) => {
  const prisma = new PrismaClient();
  const allBooks = await prisma.books.findMany();
  res.json(allBooks);
});

router.post(“/”, async (req:Request, res:Response, _next:NextFunction) => {
  const prisma = new PrismaClient();
  const data = { data: req.body };
  const book = await prisma.books.create(data);
  res.json(book);
});

router.put(“/”, async (req:Request, res:Response, _next:NextFunction) => {
  const prisma = new PrismaClient();
  const data = { where: { id: req.body.id }, data: req.body };
  const book = await prisma.books.update(data);
  res.json(book);
});

router.delete(“/”, async (req:Request, res:Response, _next:NextFunction) => {
  const prisma = new PrismaClient();
  const data = { where: { id: req.body.id } };
  const book = await prisma.books.delete(data);
  res.json(book);
});

module.exports = router;
```
## Prisma studioの起動
以下のコマンドを実行すると、Prisma studioというデータベースを操作するためのGUI(localhost:5555)が起動します。
```
npx prisma studio
```
![Prisma studio画面イメージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584922/903886f4-0c03-a54a-fd09-dad389937a40.png)

# おわりに
Prismaは機能や記述がシンプルなので使いやすく、TypeScripとの相性の良さという点でも積極的に利用したいツールだと実感しています。
また、冒頭でも述べましたが「フロントエンドもバックエンドも同じ言語(JavaScript / TypeScript)で実装したい」、「データベースには不慣れだが手軽にAPIを実装したい」とニーズに応えてくれるのでおすすめしたいです。
今回は簡易的な部分しか触れませんでしたが、今後も他の機能を試して理解を深めたいと考えています。
また、随時本記事に反映し更新予定です。

# 参考資料
[Prisma](https://www.prisma.io/)
[Prisma: Node.js & TypeScript向けの完璧なORM](https://zenn.dev/kanasugi/articles/a082bd39c5bdf2)
[Node.js(Express.js)環境でPrisma ORMを使いこなすための基礎](https://reffect.co.jp/node-js/prisma-basic)