Webのあれこれ

アイキャッチアイコンゼロから始めるExpressとPrisma入門

カテゴリ: Node.js

  • 作成日:2023/05/28

目次

    今回は、Web開発初心者・バックエンド初級者向けの記事になります。
    私自身は、フロントエンドの開発が主なので普段はNext.jsを触っていますが、API Routesや先日安定版になったApp Routerなど、バックエンド・インフラ寄りの知識も必要になってきました。
    そこで、一から学習してみよ〜ということでExpressとPostgreSQL・Prismaについて学習しました。

    Expressとは?

    Expressは、Node.jsのための軽量で柔軟なWebアプリケーションフレームワークで、WebサーバーやAPIの開発に非常に適しています。
    Node.js自体は提供するAPIが少ないですが、Expressでは、HTTPリクエストのルーティング、ミドルウェアの使用、テンプレートエンジンのサポートなど様々な機能を提供します。

    そもそもNode.jsとは?

    これは基本ですがNode.jsは言語ではなく、JavaScriptをサーバーでも動くようにするランタイム環境のことです。これにより、JavaScriptはクライアントサイドだけでなく、サーバーサイドでのプログラミングにも使用できます。
    Node.jsの代表的なフレームワークとしては、今回紹介するExpressの他にNestJS、Fastifyなどがあります。
    また、Web制作・Webアプリ開発において使われる、gulpやwebpack、npmなどのツールもNode.js上で動作しています。

    フロントエンドだけでなく、Web業界全体的にとても技術の流れが早いです。
    以下の記事でも紹介されていますが、Honoや、Fastifyなどが次世代のフレームワーク候補として今注目されています。
    https://dev.to/ronanru/stop-using-expressjs-in-202-3kc

    ただ、Expressはドキュメントや技術記事が豊富なため、PrismaやNode.jsのキャッチアップをするくらいでしたら問題ないと思っています。
    *また、NestJSをインストールする際には、Expressがデフォルトでインストールされます。ただし、Fastifyへの切り替えも可能なようです。
    余裕があったら、HonoやFastifyを触れるといいかもしれませんね!

    Prismaとは?

    Prismaは、Node.jsとTypeScriptで使われるオープンソースのデータベースツールです。SQLおよびNoSQLデータベースに対応し、データベーススキーマのマイグレーション、データモデリング、そして強力なクエリビルダーを提供します。
    通常は、SQL文を書くことでデータベースの操作をしますが、PrismaなどのORMと言われるものでは、SQL文を知らなくてもメソッドで処理を書くことができます。型保管も効くし、メソッドチェーンで書けるのでJavaScriptになじみがあるととてもわかりやすいですね。

    特にフロントエンドが主な開発だと、直接SQL文を書くことはあまりなくPrimaなどのORMを使うことが多いかと思います!

    環境構築

    まずは、通常通りディレクトリを作成してください。
    その中にserver.jsを作成します。このファイルの中にExpressの処理を書いていきます。

    必要なパッケージをインストールします(今回はyarnを使います)。

    yarn add prisma @prisma/client express nodemon

    インストールが完了したら、package.jsonでnodemonの設定を変更します。

      "scripts": {
        "start": "nodemon server.js"
      },

    上記のようにすることで、nodemonがソースコードの変更を監視し、自動で再起動してくれます。ホットリロード的な役割ですね。

    早速サーバーを起動してみましょう!
    server.js

    const express = require("express");
    const app = express();
    const PORT = 3000;
    
    app.listen(PORT, () => {
      console.log("Server is running on PORT:", PORT);
    });

    これでコンソールにServer is running on PORT: 3000と出ればOKです!
    ポート番号は任意の数字にしてください。

    Prismaの設定

    Express側の設定は終わったので、次にPrismaの設定をします。

    npx prisma init

    実行すると、 prisma > schema.prismaが作成されます。
    以下のようなPostgreSQLが指定されたファイルが生成されます。
    MySQLを使いたい場合は、providerを変更してあげればOKです!

    // 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ファイルも生成されます。
    以下のように変更すればOKです。

    DATABASE_URL="postgresql://{your-postgresql-role-name}:{your-postgresql-password}@localhost:5432/{your-created-database}?schema=public"

    PostgreSQLの用意ができてない方は、Dockerを使うか、ローカルにインストールするか、ダウンロードする必要があります。
    軽く解説しておくと、
    {your-postgresql-role-name}は、ロールを入力してください。要はユーザー名ですね。デフォルトだとpostgresというロールが存在しているはずです。
    {your-postgresql-password}は、設定したパスワードになります。ダウンロード時・ロールを新しく作成したタイミングで入力するはずです。
    {your-created-database}は、作成したデータベース名を入れます。後述します。
    localhost:5432はPostgreSQLをインストールしたら5432になっていますが、変更した場合などこのポート番号も変更してください。

    今回は、{your-created-database}のを新しく作成するデータベースところも少し解説します。
    まず、PostgreSQLサーバーを起動します。今回は、ローカルにインストールしたという設定で進めます。
    postgres -D <パス> でサーバーが起動できます。

    postgres -D /usr/local/var/postgres@14


    次に、データベースと接続をします。
    ターミナルをMacだと⌘Tを押して分割します。

    // 通常の接続
    psql -d postgres
    
    // ユーザー名(ロール)を指定して接続
    psql -U <your-postgresql-role-name> -d postgres


    上記のようにすると、postgresコマンドが使えるようになります。


    postgres=> の中に書いていきます。
    いくつか頻出のコマンドを紹介します。(Mac向け:Windowsの方は\¥に置き換えてください)

    // ユーザー一覧の確認
    \du
    
    // データーベースの切断
    \q
    
    // オーナーを指定してDBの作成
    CREATE DATABASE <your-create-database> WITH OWNER <your-owber-name>;
    
    // データベースの削除
    DROP DATABASE <your-delete-database> ;
    
    // データベースの確認(リスト)
    \l


    上記で紹介しているオーナー(ロール)を指定して、DBを作成しましょう!
    そして、DBが作成できているか\lで確認して表示されればOKです。

    postgres=> CREATE DATABASE "prisma-test" WITH OWNER "postgres-user";
    CREATE DATABASE
    postgres=> \l
                                                  List of databases
          Name    |     Owner      |  Encoding  |  Collate     |      Ctype    |  Access privileges
    -----------------+-----------------+-------------+----------------+---------------+-----------------------------
     prisma-test | postgres-user |    UTF8    | ja_JP.UTF-8 | ja_JP.UTF-8 |
    (7 rows)
    
    postgres=>


    ↑テーブルが崩れてしまって見にくくすみません。。ただこのようになればDBが作成できています!(他の部分はカットしています)
    注意として、最後に;が必要なのと、名前がhoge-fooのようになるときは、"hoge-foo"のようにしてください。

    ここで作成したprisma-testというDBを先ほどの{your-created-database}に入れてください。
    今後、データを挿入したり削除したりしますが、今後の操作は全てPrismaで行います。
    もちろん、Prismaで作成したデータでも、PostgreSQLでデータベースに移動(\c <db-name>)して\dコマンドを打つとDBの中身を確認することが可能です。
    今回はその確認なども含めて、全てPrismaを通して行います。

    DBの中身の作成

    DBのテーブル設計は、Prismaで行います。
    schema.prisma

    model Posts {
      id Int @default(autoincrement()) @id
      createdAt DateTime @default(now())
      text String 
      checked Boolean @default(false)
    }


    Prismaでは、model ** とするとテーブルの作成ができます。
    詳細は、Prismaのドキュメントをご覧ください。

    idとcreatedAtは@default()としているため、何も指定せずに自動で入力してくれます。
    textは文字列が入り、checkedはbooleanが入るようになります。
    これで準備は整ったのでマイグレートしましょう!

    npx prisma migrate dev --name init

    そうすると、同じディレクトリにmigrationsというディレクトリが作成できました。
    以下のようなsqlファイルができていればOKです!

    migration.sql

    -- CreateTable
    CREATE TABLE "Posts" (
        "id" SERIAL NOT NULL,
        "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
        "text" TEXT NOT NULL,
        "checked" BOOLEAN NOT NULL DEFAULT false,
        CONSTRAINT "Posts_pkey" PRIMARY KEY ("id")
    );


    SQL文を書くことなく、PrismaでSQLファイルを作成することができました🎉

    データをGUIで入れてみる

    Prismaでは、Prisma StudioというツールでGUIでデータを確認したりインサート(データの登録)することができます。
    以下のコマンドを実行してください。

    npx prisma studio


    そうすると、5555というポート番号で自動的にブラウザが立ち上がると思います。
    Postsという名前で作成したので、選択します。
    先ほど作成した、「id / createdAt / text / checked」という名前のテーブルがあるはずです。
    「Add record」を押して手動で追加しみてましょう(デフォルト値設定しているので、textの追加だけでOK)。

    リロードして消えなければOKです!

    Expressで操作しよう

    先ほど作成したserver.jsに処理を書いてきます。
    まずは、ミドルウェアを使用するためにExpressの処理を書いてきます。
    server.js

    // Middleware
    app.use(express.json());

    続いてデータの取得をしてみます。
    server.js

    // データの取得
    app.get("/posts", async (_, res) => {
      const posts = await prisma.posts.findMany();
      return res.json(posts);
    });


    getメソッドを使用します。第一引数にはエンドポイントを指定します。今回は、/postsとしているので、ブラウザで/postsとするとデータが取得できるようになります。
    第二引数は、コールバック関数の処理を書きます。先ほどpostsという名前でモデルを作成したので、prisma.postsとします。そして、findMany()は、条件に一致するレコードを全て取得することができます。
    実際にアクセスすると、先ほど直接入力したデータが見れればOKです🚀

    SQLで書くとどうなる?

    Prismaを使わずに、Express + PostgreSQLで書くと以下のようになります。

    // 例:データの取得をSQLで書いた場合
    app.get("/users", (_req, res) => {
      pool.query("SELECT * FROM users", (err, results) => {
        if (err) throw err;
        return res.status(200).json(results.rows);
      });
    });

    pool.query()の第一引数にSQLの処理を書いていますね。今回は、取得するだけでしたのであまり分かりにくいですが、特定のidを操作したり、エラーの場合の処理をSQL文で書くとコードも冗長になり、処理も多くなってしまいます。

    データの作成・追加・削除

    まずはデータの作成をしてみましょう!
    作成するために、今回はPostmanを使います。
    左上の+ボタンから新しいワークスペースを作成し、New Requestを作成してください(今回は詳細なPostmanの説明は省きます)。

    試しにGETメソッドで叩いてみましょう。

    先ほどブラウザでアクセスした時と、同じように取得できていればOKです!
    続いてデータの作成するためのコードを書いていきます。
    server.js

    // データの作成
    app.post("/posts", async (req, res) => {
      const { text, checked } = req.body;
      const posts = await prisma.posts.create({
        data: {
          text,
          checked,
        },
      });
      return res.json(posts);
    });


    ここで、/postsエンドポイントに対してPOSTメソッドを使います。ユーザーが新しい投稿を作成したいときにこのエンドポイントを使用します。
    ユーザーから送信されるデータは、req.bodyというオブジェクトの中に格納されています。このオブジェクトからtextとcheckedの2つのフィールドを取得します。

    また、今回は作成するため、create({data: {}}) ですね。とても直感的で分かりやすいですね!

     const { text, checked } = req.body;

    ちなみにここでは、ミドルウェアを使用しリクエストのbodyを解析してtextとcheckedを取り出しています。
    このデータがデータベースに格納されます。

    今回はbodyにデータを入れます。
    rawを選択し、データはJSONにしてください。

    以下のように追加されていればOKです!
    もう一度GETメソッドを叩き、追加されていれば成功です!




    ちなみに、IDなど指定して特定のデータの取得をすることも可能です。
    server.js

    // 特定のデータの取得(ID)
    app.get("/posts/:id", async (req, res) => {
      const { id } = req.params;
    
      const posts = await prisma.posts.findUnique({
        where: {
          id: Number(id),
        },
      });
      return res.json(posts);
    });
    
    


    エンドポイントを/posts/:idのようにして、paramsidを取り出します。
    where{}でフィルタリングすることが可能です。

    <結果>

    先ほど追加したデータがブラウザでもみれました!

    これまでの容量で、データの変更や削除も可能です。
    メソッドなどが変わるだけで基本的な考え方は変わりません。

    // データの変更
    app.put("/posts/:id", async (req, res) => {
      const { id } = req.params;
      const { text, checked } = req.body;
    
      const updatedPost = await prisma.posts.update({
        where: {
          id: Number(id),
        },
        data: {
          text,
          checked,
        },
      });
      return res.json(updatedPost);
    });
    
    // データの削除
    app.delete("/posts/:id", async (req, res) => {
      const { id } = req.params;
    
      if (isNaN(id)) {
        return res.status(400).json({ error: "Invalid ID" });
      }
    
      const deletedPost = await prisma.posts.delete({
        where: {
          id: Number(id),
        },
      });
      return res.json(deletedPost);
    });


    *ちなみに、変更する際はPUTメソッド、削除する際はDELETEメソッドになります。
    <結果>

    ↑textとcheckedが書き換えられていますね

    ↑続いて、id: 3が削除されていることが分かります。

    おわり

    少し雑になってしまった部分もありますが、ExpressとPrisma・PostgreSQLについて解説しました。
    フロントエンドエンジニアでも、バックエンドやインフラの知識も必要になってきているのでサーバーでどういう処理ができるのかなどざっと知っておく必要があると思います。
    Express・Prisma・Postmanなどを使うととても簡単に検証できるのでぜひいろいろ試していただければと思います✨

    この記事へのコメント

    この記事にはまだコメントがありません。

    お気軽にコメント残してください📝

    © 2022 wadeenOpenMojiis licensed underCC BY-SA 4.0