Prisma+Expressを使ってデータベースを操作する

こんにちは!筆者の「hima-code」です。

前回「Express」に関する記事を紹介して、「json」の変換かExpressのさらに詳しい解説記事を出すと書きましたが、その前に「Prisma」を導入して「MariaDB」等のデータベースと連携する準備を整えておきたいと思います。

「Prisma」とはJavaScriptを使ってSQL文を扱わなくてもデータベースの基本操作である「CRUD」を行うことができるORMライブラリになります。「TypeScript」との相性も良いので、同時に導入して使い方を覚えていくと良いかと思います。それでは導入していきましょう。

1.Expressのプロジェクトを作成する

前回記事をベースにそこにPrismaを導入していきますので、Expressのプロジェクトを作成していただくか、記事を参考にプロジェクトを作成してください。

2.TypeScriptをプロジェクトにインストールする

cdコマンドでプロジェクトフォルダをカレントディレクトリに変更します。今回は「sandbox-server」という名前のサーバーをベースに進めていきます。

$ cd sandbox-server

そうしたら、npmコマンドを使用してTypeScriptをインストールします。

$ npm init -y
$ npm install typescript tsx @types/node --save-dev

次にTypeScriptを初期化します。

$ npx tsc --init

ここまでターミナルにコマンドを入力しライブラリのインストールが終わったら、次は「Prisma」をインストールします。

3.Prismaのインストール

次にPrisma CLIをインストールします。これはプロジェクト上で「prisma」コマンドを使用できるようにするライブラリになります。

$ npm install prisma --save-dev

そして最後に、先ほど入れた「Prisma CLI」コマンドを使用して「Prisma ORM」をセットアップします。

$ npx prisma init --datasource-provider mysql

今回は「MariaDB」を使用するので、オプションの–datasource-providerに「mysql」をセットします。ここは使うDBMSによって変わるので、SQLiteを使用するときは「sqlite」、PostgreSQLを使用するときは「postgres」に変更してコマンドを入力してください。

最後にEnterキーを押してPrismaのスキーマファイルである「schema.prisma」が作成され、MariaDBと連携する準備が整いました。

4. schema.prismaにデータモデルを書き込む

プロジェクト直下に「prisma」フォルダが作成され「schema.prisma」ファイルが作成されました。それでは、「Articles」データモデルを作成します。今回は簡易的な記事投稿のデータベースを作成することを考えます。schema.prismaファイルを以下のように書き換えます。

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

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

//追加
model Articles {
  id     Int    @id @default(autoincrement())
  title  String
  content String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

データモデルを追加したら、ローカルでMariaDBサーバーを立ち上げます。この記事では説明しませんので、次回以降にデータベースサーバーを立ち上げる手順を解説します。

そして.envファイルが作成されているかと思うので、そのファイルも下記のように書き換えます。

DATABASE_URL="mysql://user:password@localhost:3306/app"

このように書き換えると、MariaDBにユーザー名「user」、パスワード「password」、データベースURL「localhost」、ポート番号「3306」、データベース名「app」で接続するという文字列を設定できます。自分で設定したデータベースの状態に応じて接続文字列の中身を変更してください。データベースサーバーに指定の名前を持つデータベースが存在しなければ、自動で作成されます。今回は「app」データベースが作成されます。

5.マイグレーションを行う

保存したいデータ構造をモデルとして定義したら、その構造をデータベース上に実際に作成していきます。下記のコマンドをターミナルで実行して、作成していきます。

$ npx prisma migrate dev --name init

接続文字列の情報が間違っていなければ、データベース上にモデルとして定義した「Article」がテーブルとして作成されています。

6.prismaインスタンスを作成し、データの書き込みを行う

prismaインスタンスを作成し、データベース接続用のオブジェクトを作成していきます。「シングルトンパターン」でインスタンス化を行い、サーバーを立ち上げているときは一つのprismaオブジェクトしかないことを保証したほうが、開発サーバーで動かしているときに、パフォーマンスが悪くなりにくいです。しかし、初学者の方には少し難しい話になるので、まずは基本となる書き方でインスタンス化を行っていきます。

プロジェクト直下に「lib」フォルダを作成し、その中に「prisma.ts」ファイルを作成してください。prisma.tsには以下のように記述してprismaインスタンスを作成します。

import { PrismaClient } from '@prisma/client'

export const prisma = new PrismaClient()

export default prisma

ここまで来たらデータベースとの接続準備は完了になります。

7. ルーティングと処理をサーバーファイルに記述

「app.js」ファイルに以下のコードを記述します。

import express from 'express'
import { prisma } from './dist/prisma.js'

const app = express()
const port = 4000

app.use(express.json())

app.get('/', (req, res) => {
    res.send('Hello World')
})

app.post('/articles', async (req, res) => {
    const { title, content } = req.body
    const article = await prisma.articles.create({
        data: {
            title: title,
            content: content,
        }
    })
    res.json(article)
})

app.get('/articles', async (req, res) => {
    const articles = await prisma.articles.findMany()
    res.json(articles)
})

app.listen(port, () => {
    console.log(`Server is running on port ${port}`)
})

今回は「GET」と「POST」リクエストを「/articles」にルーティングを設定して、「GET」リクエストではデータベースの「articles」に登録されているデータをすべて返します。「POST」リクエストではデータを受け取ってデータベースに保存する処理をします。

8.設定ファイルの変更

「package.json」と「tsconfig.json」の二つのファイルを変更します。まずはpackage.jsonファイルを以下のように修正します。scriptの部分にbuildコマンドを追加します
“scripts”: {
“test”: “echo \”Error: no test specified\” && exit 1″,
“start”: “node app.js”,
“build”: “tsc –build”
},

このビルドコマンドは「TypesScriptファイル」をコンパイルして「JavaScriptファイル」にするコマンドです。node.jsでは直接的にTypeScriptファイルを実行できないので、コーディングした後はJavaScriptファイルに直す必要があります。(今回は紹介しませんがts-nodeで直接TypeScriptファイルを実行する方法もあります。)

そしたらコンパイルの設定をするために「tsconfig.json」に変更を加えます。

{
  "compilerOptions": {
    "target": "ES2022",  
    "module": "NodeNext",  
    "moduleResolution": "nodenext",  
    "sourceMap": true,  
    "outDir": "./dist",  
    "removeComments": true,  
    "noEmitOnError": true,  
    "esModuleInterop": true,  
    "forceConsistentCasingInFileNames": true,  
    "strict": true,  
    "noImplicitAny": true,  
    "skipDefaultLibCheck": true,  
    "skipLibCheck": true  
  }
}

詳しいコンパイルオプションの説明は省きますが、JavaScriptファイルが「ESModules」としてコンパイルできる設定などを書き込んでいます。また「outDir」オプションでは、カレントディレクトリと同階層にdistフォルダを作成して、その中にコンパイルによって生成された「JavaScript」ファイルが配置されます。

最後に以下のコマンドをターミナルに打ち込んで、コーディング自体は終了になります。

$ npm run build

distフォルダの中にファイル群が生成されたら準備完了です。

9.サーバーの起動

ここまで来たら、あとはサーバーを起動するだけになります。以下のコマンドをターミナルに打ち込んでサーバーを起動します。

$ npm run start

「Server is running on port 4000」という文字がターミナルに出力されたら終了です。

10.リクエストを送信する

リクエストを送信するにはテストコードを記述してもよいのですが、ここでは「Postman」やVSCodeの拡張機能である「Thunder Client」などのWebAPI開発時に便利なツールを紹介します。今回は新しくアプリケーションを入れる手間を省略するためにVSCodeを使っている人であればだれでも無料で使用することができる拡張機能「Thunder Client」を使ってテストを進めていきます。サイドバーにある「拡張機能」から検索バーを使って「Thunder Client」と入力して出てきたものをインストールします。

インストールが終わったら、再度バーに出てくる稲妻のアイコンをクリックして「New Request」をクリックします。そしたら下の画像のように「POST」リクエストに変更、URLを「http://localhost:4000/articles」に変更、Bodyを選択、JSONを選択し、JSON Contentの中に送りたいJSONデータを入力します。

今回送るJSONデータは下記のものになります。コピペするか自分で入力してみてください。

{
  "title": "明日の天気について",
  "content": "晴れです"
}

準備ができたら「Send」ボタンをクリックしてリクエストを送信します。送信に成功するとレスポンスとして下の画像の赤枠の部分がサーバーから送信されます。Statusとして200番が帰ってくれば、リクエストは成功になります。

そうしたらまた「New Request」をクリックして今度は登録したデータを確認してみましょう。正常に登録できていれば、今度は先ほど送った内容が見れるはずです。今度は「GET」と「http://localhost:4000/articles」のみを入力して「Send」ボタンを押してみましょう。

上の画像では2件のデータがデータベースに記録されているので、2件目以降も取得されていますが、記事の内容通りに進めていれば、先ほど登録した1件のみが取得されているはずです。

これで基本となるCreateとReadの処理が書けるようになりました!

11.最後に

ここまでお付き合いいただきありがとうございました。RESTFulなAPIサーバーは目に見えるアプリケーションの部分を触っているだけでは見えてこないし、通信まわりは勉強しずらいところの一つかなと個人的には思ってます。(ガチの初学者のときは通信は読んでも意味不明でした)まだまだ、Prismaの基本メソッドの学習やトランザクションの理解、Dockerを使ったデータベースサーバーの作成の仕方、そしてAPIサーバーはWebページからどのように使うのかなどは説明していないので、そこらへんは頑張って解説記事を上げていく予定です。