はじめに
この記事は、Node.jsとPostgreSQLでシンプルなアプリケーションを作成シリーズの2回目です。
前回の記事では、Node.jsで作ったシンプルなアプリケーションがBTP上のPostgreSQLに接続できるところまでを確認しました。
この記事のゴール
Node.jsアプリケーションからPostgreSQLのテーブルに対してCRUD処理を行えるようにする
ステップ
Read処理(全てのレコード)
Read処理(指定したidのレコード)
Create(Insert)処理
Update処理
Delete処理
1. Read処理(全てのレコード)
srvフォルダの配下にdb-op.jsというファイルを作成し、ここにCRUD処理を記述します。
プロジェクトの構成は以下のようになります。
node-postgres-sample
└ srv
|- package.json
|- db-conn.js
|- db-op.js
└ server.js
└ mta.yaml
srv/db-op.js
'use strict'
function getAll(db,res) {
const query = 'SELECT * FROM products'
db.manyOrNone(query)
.then((data) => {
// success
res.status(200).json(data)
})
.catch((error) => {
// error
res.status(500)
res.end(`Error accessing DB: ${JSON.stringify(error)}`)
})
}
module.exports = {
getAll: getAll
}
function getAllはpg-promiseのDatabaseオブジェクトを引数に取ります。DatabaseのmanyOrNoneというメソッドを使い、productsテーブルから全件を取得します。manyOrNoneは複数のレコードが返ってくることが想定されるときに使用します。
server.jsに処理を追加します。/productsというパスが指定されたら、getAllメソッドを呼ぶようにします。
srv/server.js
'use strict';
const express = require('express')
const bodyParser = require('body-parser')
const dbConn = require('./db-conn')
const dbOp = require('./db-op') //追加
var _db = undefined
...
app.get('/products', function(req, res) {
dbOp.getAll(_db, res)
})
Cloud Foundryにデプロイ後、/productsのパスを指定するとすべてのレコードが取得できます。
2. Read処理(指定したidのレコード)
URLで/products/1のようにidを指定した場合に、指定されたidのレコードを返す処理:getOneを追加します。
srv/db-op.js
...
function getOne(db, res, id) {
db.one({
name: 'find-product',
text: 'SELECT * FROM products WHERE id = $1',
values : [id]
})
.then((product) => {
res.status(200).json(product)
})
.catch((error) => {
// error
res.status(500)
res.end(`Error accessing DB: ${JSON.stringify(error)}`)
})
}
module.exports = {
getAll: getAll,
getOne: getOne
}
Databaseオブジェクトのoneというメソッドを使い、productsテーブルから指定された1件のレコードを取得します。oneは1件の結果が必ず返ってくることが想定されるときに使用します。
oneに渡しているのはPreparedStatementというオブジェクトです。ここでは以下のパラメータを指定しています。
パラメータ
意味
name
任意の名前。1つのセッション内でユニークである必要がある
text
クエリストリングまたはQueryFileオブジェクトを指定する。クエリストリングでは、$1, $2といった変数を使用することができる
values
クエリストリングに入る変数を配列で指定する
server.jsに処理を追加します。/products/:idというパスが指定されたら、getOneメソッドを呼ぶようにします。
srv/server.js
app.get('/products/:id', function(req, res) {
dbOp.getOne(_db, res, req.params.id)
})
デプロイ後、/products/1を指定すると、指定したレコードのみが返ってきます。
存在しないidを指定した場合はエラーになります。
3. Create(Insert)処理
JSON形式で渡したデータをproductsテーブルに登録する処理:insertOneを追加します。
srv/db-op.js
function insertOne(db, res, newData) {
db.one({
name: 'insert-product',
text: 'INSERT INTO products(name, price) values($1, $2) RETURNING *',
values : [newData.name, newData.price]
})
.then((product) => {
res.status(201).json(product)
})
.catch((error) => {
// error
res.status(500)
res.end(`Error accessing DB: ${JSON.stringify(error)}`)
})
}
module.exports = {
getAll: getAll,
getOne: getOne,
insertOne: insertOne
}
insertOneで呼んでいるのは、getOneと同じDatabaseオブジェクトのoneメソッドです。RETURNINGというのは見慣れない構文ですが、これはINSERT、UPDATE、DELETEの結果更新されたレコードを取得するための命令です。
server.jsに処理を追加します。/productsというパスでPOSTリクエストが来たら、insertOneメソッドを呼ぶようにします。
srv/server.js
app.post('/products', function(req, res) {
dbOp.insertOne(_db, res, req.body)
})
Postmanでテストします。
この後/productsを見ると、新しいレコードが追加されています。
4. Update処理
productsテーブルを更新する処理:modifyOneを追加します。
srv/db-op.js
function modifyOne(db, res, id, newData) {
db.one({
name: 'update-product',
text: 'UPDATE products set name = $1, price = $2 WHERE id = $3 RETURNING *',
values : [newData.name, newData.price, id]
})
.then((product) => {
res.status(200).json(product)
})
.catch((error) => {
// error
res.status(500)
res.end(`Error accessing DB: ${JSON.stringify(error)}`)
})
}
module.exports = {
getAll: getAll,
getOne: getOne,
insertOne: insertOne,
modifyOne: modifyOne
}
server.jsに処理を追加します。/products/:idというパスでPUTリクエストが来たら、modifyOneメソッドを呼ぶようにします。
srv/server.js
app.put('/products/:id', function (req, res) {
dbOp.modifyOne(_db, res, req.params.id, req.body)
})
Postmanから"banana"のレコードのpriceを110に変更しました。
5. Delete処理
指定されたレコードをproductsテーブルから削除する処理:deleteOneを追加します。
srv/db-op.js
function deleteOne(db, res, id) {
db.result({
name: 'delete-product',
text: 'DELETE FROM products WHERE id = $1',
values: [id]
})
.then((product) => {
res.status(200).end('OK')
})
.catch((error) => {
// error
res.status(500)
res.end(`Error accessing DB: ${JSON.stringify(error)}`)
})
}
module.exports = {
getAll: getAll,
getOne: getOne,
insertOne: insertOne,
modifyOne: modifyOne,
deleteOne: deleteOne
}
ここではDatabaseオブジェクトのresultというメソッドを使っています。resultは結果が返ってくることを期待しない場合に使用します。CREATE, UPDATE処理ではRETURNINGで更新されたレコードを取得していましたが、ここでは特に結果を受け取らないのでresultメソッドを使用しています。
server.jsに処理を追加します。/products/:idというパスでDELETEリクエストが来たら、deleteOneメソッドを呼ぶようにします。
srv/server.js
app.delete('/products/:id', function(req, res) {
dbOp.deleteOne(_db, res, req.params.id)
})
削除に成功すると、'OK'が返ってきます。
一覧を見るとレコードが削除されたことが確認できます。
まとめ
この記事では、以下を実施しました。
Node.jsアプリケーションからPostgreSQLのテーブルに対してCRUD処理を行えるようにする
次回はXSUAAサービスを使って認証を追加したいと思います。
参考
cloud-cf-helloworld-nodejs/Chapter 2: Node.js RESTful API persists data in PostgreSQL DB
PostgreSQL Tutorial
PostgreSQLのドキュメント
pg-promiseのドキュメント
↧