Express.jsとPostgreSQLでAPIを作成する

データベース

こんにちは。

今回は、ローカルにPostgreSQLでデータベースを用意して、ExpressでREST APIを作成してみたいと思います。

GETリクエストとPOSTリクエストに対応します。

PostgreSQLでデータベースとテーブルを作成する

データベースの作成

PostgreSQLがローカルにインストールされている前提で進めます。

まずは、ログイン。

psql -U <ユーザーネーム>

<ユーザーネーム>の部分は、デフォルトだとpostgresのはずです。

パスワードを求められるので、入力してログインします。

ログインできたらデータベースを作成します。

postgres=# CREATE DATABASE express_postgres;

データベースの名前は、express_postgresとしました。

データベースが作成できましたので、その中にテーブルを作成しましょう。

productsテーブルの作成

今回はシンプルにproductsテーブルのみを作成します。

まずは先程作成したデータベースexpress_postgresに接続します。

postgres=# \c express_postgres

\(バックスラッシュ)cは、データベースに接続するpsqlのコマンドです。

接続できたらproductsテーブルを作ります。

express_postgres=# CREATE TABLE products
 (id serial PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  price integer NOT NULL);

idと商品名(name)と値段(price)のcolumnを作成しました。

idのデータ型をserialにしてあるので、データを入れるごとにidは1ずつ増えていきます。
nameは最大255文字入れられます。NOT NULLなので空欄にはできません。
priceは整数で、こちらもNOT NULLです。

\d products

と打つと、productsテーブルの詳細が見られます。

productsテーブルの詳細
productsテーブルの詳細

テーブルの作成ができました。

productsテーブルに商品データを入れる

先ほど作成したproductsテーブルに商品データを入れていきます。

express_postgres=# INSERT INTO products(name, price) VALUES ('赤い帽子', 3980);

と打つと、3980円の赤い帽子がproductsテーブルに挿入されます。

データを確認してみましょう。

express_postgres=# select * from products;

と打つと、productsテーブルの中のすべてのデータが表示されます。

赤い帽子が挿入された
赤い帽子が挿入された

同様にデータを入れて、今のテーブルはこんな感じです。

白いTシャツと、黒いジャケットを追加した
白いTシャツと、黒いジャケットを追加した

これでPostgreSQL側の準備は完了です。

Express generatorでExpress.jsをインストール

Express.jsをインストール

ローカルにプロジェクトフォルダを作って、その中でターミナルにて

npx express-generator

を実行します。

すると各種ファイルと、package.jsonが作られるので、

npm install

を実行します。

nodemonを入れる

ついでに開発用にnodemonを入れておきましょう。

npm install --save-dev nodemon

と打ってインストールします。

次に、package.jsonの”scripts”を少し修正します。

“start”のコードをコピペして、”dev”を作ります。
“node”の部分を”nodemon”に変えます。

  "scripts": {
    "start": "node ./bin/www",
    "dev": "nodemon ./bin/www"
  },

これでターミナルで、

npm run dev

と打つと、サーバーが立ち上がり、ファイルを修正して保存する度にサーバーが再起動されます。

この状態で、http://localhost:3000/にアクセスするとデフォルトのExpressのページが表示されます。

Expressのデフォルトページ

node-postgresでデータベースと接続する

node-postgresのインストール

node-postgresは、PostgreSQLに接続するnode.jsモジュールです。

npm install pg

でインストールします。

dbフォルダを作ってPostgresに接続するコードを書く

インストールが完了したら、Suggested Code Structureを参考に接続用ファイルを作成します。

まずルート直下にdbフォルダを作成して、その下にindex.jsファイルを作成します。

- bin/
- node_modules/
- public/
- routes/
- app.js
- package.json
- package-lock.json
- db/
  - index.js <--- このファイルでPostgresに接続する

db/index.jsの中身はこんな感じにしました。

const { Pool } = require("pg");

const pool = new Pool();

module.exports = {
  async query(text, params) {
    return await pool.query(text, params);
  },
};

async・await文を使ってシンプルに仕上げました。

データベースへのアクセス情報を追加する

Connectingのページを参考に、先程のindex.jsにデータベースへのアクセス情報を追加します。

※Github等でコードを公開する際は、.gitignoreやdotenvを使ってアクセス情報が公開されないように気をつけましょう。

ここではURI形式で接続します。このURIはダミーです。

db/index.js

const { Pool } = require("pg");
const connectionString =
  "postgresql://dbuser:secretpassword@localhost:5432/express_postgres";

const pool = new Pool({ connectionString });

module.exports = {
  async query(text, params) {
    return await pool.query(text, params);
  },
};

・dbuserは、データベースのユーザー名に差し替え
・secretpasswordは、データベースのパスワードに差し替え
・@のところはデータベースのホストの場所で、今回はローカルなのでlocalhost
・:のところはデータベースのポート番号(postgresのデフォルトは5432)
・最後の/以下は、接続するデータベース名

これでPostgresのデータベースに接続する準備ができました。

GETリクエスト周辺のコードを書く

次は、GETリクエストがあった場合に実行されるコードを書いていきます。

リクエスト: app.js -> Route -> Service -> Model -> PostgreSQL
レスポンス: app.js <- Route <- Service <- Model <- PostgreSQL

という感じの流れを作ります。

Modelの作成

先ほど作成したdb/index.jsを利用して、クエリ文をかいてデータベースからデータを取り出すModelを用意します。

ルート直下にmodelsというフォルダを用意して、その下にproducts.jsを作成します。

models/products.js

const db = require("../db");

module.exports = class ProductsModel {
  async getProducts() {
    const text = `SELECT id, name, price from products`;
    const values = [];
    try {
      const res = await db.query(text, values);
      console.log(res.rows);
      if (res?.rows[0]) {
        return res.rows;
      }
      return [];
    } catch (err) {}
  }
};

class ProductsModelを作成してexportします。

class ProductsModelの中にgetProducts()を作成して、先程用意したdb/index.jsを使ってデータベースにクエリ文を送ります。

返ってきたres.rowsの中身が空でなければres.rowsを返します。空であれば空のArrayを返します。

うまく行けば、productsテーブルにある全てのid, name, priceが返って来ます。

これで一旦GETリクエストのModelはできました。

Serviceの作成

次はModelとRouteをつなぐ、Serviceを作成します。

ルート直下にservicesというフォルダを作成し、その下にproducts.jsを作成します。

services/products.js

const productsModel = require("../models/products");
const productsModelInstance = new productsModel();

module.exports = class productsService {
  async getProducts() {
    try {
      const res = await productsModelInstance.getProducts();
      return res;
    } catch (err) {}
  }
};

こちらでも、class productsServiceを作成してexportしています。

先程作ったproductsModelを呼び出して、インスタンス化してgetProducts()を使っています。

返ってきたものを、更に返します。この場合はproductsのArrayが返ってくるはずです。

これでGETリクエストのServiceも完成。

Routeの作成

次はproducts用のrouteを作成します。

既に存在するroutesフォルダの下にproducts.jsを作成します。

routes/products.js

var express = require("express");
var router = express.Router();
const productsService = require("../services/products");
const productsServiceInstance = new productsService();

router.get("/", async function (req, res, next) {
  try {
    const response = await productsServiceInstance.getProducts();
    res.send(response);
  } catch (err) {}
});

module.exports = router;

ここではroutesのindex.jsやusers.jsをコピペして改変しました。

express.Router()を使ってgetリクエストのrouteを作成し、最終行でexportしています。

先程作ったproductServiceをインスタンス化して、getProducts()を使用しています。

そして返ってきたものを、res.send()を使ってレスポンスとして返しています。

これでGETリクエストのRoutesも完了です。

app.jsにrouteを追加する

最後に、既に存在するapp.jsに、先程作ったroutes/products.jsを追加します。

app.js

var createError = require("http-errors");

<中略>

var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
const productsRouter = require("./routes/products");

var app = express();

<中略>

app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/api/products", productsRouter);

<中略>

module.exports = app;

上の方で、productsRouterを用意して、真ん中あたりでapp.use()を使って、”/api/products”と対応させています。

これで、http://localhost:3000/api/productsにGETリクエストを送ると、商品リストのJSONデータが送られてくるはずです。

PostmanでGETリクエストを送ってみる

PostmanはAPI作成に使える大変便利なツールです。

これを使ってGETリクエストを送ってみたいと思います。

Postman上でワークスペースを作って、http://localhost:3000/api/productsにGETリクエストを送信します。

GETリクエストを送信する
GETリクエストを送信する

すると、JSONデータが返ってきます。

商品リストのJSONデータ
商品リストのJSONデータ

リクエストが成功した「200 OK」とともに、商品データのid, name, priceが、それぞれArray形式で返ってきましたね。

次は、POSTリクエストでデータベースのproductsテーブルに新規商品を追加してみましょう。

POSTリクエスト周辺のコードを書く

次は、POSTリクエストがあった場合に実行されるコードを書いていきます。

GETリクエスト同様に、

リクエスト: app.js -> Route -> Service -> Model -> PostgreSQL
レスポンス: app.js <- Route <- Service <- Model <- PostgreSQL

という感じの流れを作ります。

GETリクエストのときに作成したファイルに加筆していきます。

Modelの作成

まずはModelから。

models/products.js

const db = require("../db");

module.exports = class ProductsModel {
  async getProducts() {
    <省略>
  }


  async createProduct({ name, price }) {
    const text = `INSERT INTO
                  products(name, price)
                  VALUES($1, $2)
                  RETURNING *`;
    const values = [name, price];
    try {
      const res = await db.query(text, values);
      if (res?.rows[0]) {
        return res.rows[0];
      }
      return {};
    } catch (err) {}
  }
};

class ProductsModel の中に、createProduct()を追記しました。

textの中には、SQL文が書いてあります。

$1, $2とあるのはプレースホルダーで、values Arrayの順番に対応して自動的に置き換わります。

そしてレスポンスを返します。

次はServiceの作成に移りましょう。

Serviceの作成

ModelとRouteをつなぐ、Serviceです。
既存のファイルに追記します。

services/products.js

const productsModel = require("../models/products");
const productsModelInstance = new productsModel();

module.exports = class productsService {
  async getProducts() {
    try {
      const res = await productsModelInstance.getProducts();
      return res;
    } catch (err) {}
  }

  async createProduct(data) {
    try {
      const res = await productsModelInstance.createProduct(data);
      return res;
    } catch (err) {}
  }
};

createProduct()を追記しました。

GETリクエストのコードとほとんど変わらないですね。

dataは、POSTリクエストで送られてくるデータオブジェクトで、Modelの中でnameとpriceに分解されます。

次はRouteに行きましょう。

Routeの作成

Routeも既存の同じファイルに追記します。

GETリクエストのときと大体同じですが、送られてきた商品データを取得しなくてはいけません。

routes/products.js

<省略>
const productsServiceInstance = new productsService();

router.get("/", async function (req, res, next) {
  <省略>
});

router.post("/", async function (req, res, next) {
  try {
    const data = req.body;
    const response = await productsServiceInstance.createProduct(data);
    res.send(response);
  } catch (err) {}
});

module.exports = router;

req.bodyから、リクエストのbodyを取得して、dataに入れました。
これが商品データのオブジェクトで、nameとpriceが入っているはずです。

あとは先程作ったcreateProduct(data)を発動して、返ってきたものをres.send(response)で返すだけです。

app.jsには、GETリクエスト周辺で、すでにroute追加済みなので、もうPOSTリクエストができるはずです。

試してみましょう。

PostmanでPOSTリクエストを送ってみる

Postmanを使います。

今度はPOSTリクエストなのでPOSTを選択します。
URLはGETリクエストと同じ、http://localhost:3000/api/productsでOKです。

Sendボタンを押す前に、送信する商品データを作成します。

JSON形式で商品データを送信する。

URL入力欄の下部のBodyを選んでrawを選んでJSONを選びます。

すると、JSON入力欄が現れるので、JSON形式で商品データを入力します。
今回書いたコードに合わせて、nameとpriceです。

idはデータベース側で自動的に+1の数字が付与されます。

ではSendボタンを押してみましょう。

今回作成した商品データが返ってきた
今回作成した商品データが返ってきた

「200 OK」と、今回作成した商品データが返ってきました。

Postgres側でも確認してみる

きちんと商品データが追加されているかをPostgres側でも確認してみます。

今回追加した商品が増えている

きちんと青いスニーカー(12900円)が追加されていますね。

これでPOSTリクエスト周辺の記述は終わりです。

動作の確認

最後に、もういちどGETリクエストをしてみましょう。

PostmanでGETリクエスト
200 OK

はい、返ってきたJSONオブジェクトに新しい商品が追加されていますね。

こんな感じでExpress.jsとPostgreSQLでREST APIが完成しました。

コメント

タイトルとURLをコピーしました