6-1. HTTPリクエストを検査する curl コマンド
6-2. DB接続クレデンシャル
6-3. バックエンドAPIアプリの設計
6-4. connectDatabase()関数
6-5. closeDatabase(db)関数
6-6. app.get( ‘/get’ ) データ読み込み
6-7. APIとポート番号のプロキシ設定
6-8. バックエンドAPIアプリの永続化
6-9. app.get( ‘/create’ ) データ書き込み
6-10. app.get( ‘/delete’ ) データ削除
6-11. app.get( ‘/update’ ) データ更新
6-12. まとめ
フロントWEBアプリとバックエンドAPIアプリをHTTPメソッドで通信します。

6-1. HTTPリクエストを検査する curl コマンド
HTTPリクエスト:GET, PUT, POST, DELETE のコマンドでの呼び出しを参考に、バックエンドAPI機能をテストしながら開発します。ポート番号は自分の環境に合わせること。
$ curl -X GET http://127.0.0.1:3002/get
$ curl -X DELETE http://127.0.0.1:3002/delete/1
$ curl -X PUT http://127.0.0.1:3002/update/1 -H "Content-Type: application/x-www-form-urlencoded" -d "flag=111&plan=2222&result=33333"
$ curl -X POST http://127.0.0.1:3002/create -H "Content-Type: application/x-www-form-urlencoded" -d "flag=aaaa&plan=bbbbb&result=cccc"6-2. DB接続クレデンシャル
コードの中にユーザー名やパスワードを記載すると、ログインするためのクレデンシャルが漏洩するリスクがあります。これを防ぐために、コードと環境変数のファイルを分離して記述します。
Node.jsアプリを配置するディレクトリに環境ファイル[.env]を作成、もしくはDBに接続するための環境変数を追加します。
DB_HOST=DBサーバーのドメイン名(もしくはIPアドレス)
DB_USER=データベースに接続するユーザー名
DB_PASS=データベースに接続するユーザーのパスワード
DB_NAME=使うデータベース名6-3. バックエンドAPIアプリの設計
URIアクセスを待ち受けし、データベースのレコードを読み書きした結果を返す関数を設計します。
ディレクトリ[~/app]に、新しいファイル[app-api.js]を作成します。
// ----------------------------
// 初期設定:モジュール読み込み。変数定義。
// ----------------------------
const express = require("express"); // Expressモジュール読み込み
const app = express(); // アプリサーバーとしてインスタンス化
const mysql = require('mysql'); // MySQLモジュール読み込み
const cors = require('cors'); // CORS(Cross-Origin Resource Sharing)モジュールを読み込み
const port = 3003; // TCPポート番号を指定
require('dotenv').config(); //環境変数[~/app/.env]を process.env に代入
// ----------------------------
// `.bashrc` で設定した環境変数からユーザー情報を取得
// ----------------------------
// ----------------------------
// listen()メソッドを実行して3000番台ポートで待ち受け。
// ----------------------------
var server = app.listen(port, function(){
console.log("Node.js待ち受けポート:" + server.address().port);
});
// ----------------------------
// WEBブラウザは、異なるオリジン(ドメイン)へのアクセスは基本的にブロックする。
// CORS()関数は、リモートサーバーからのPOST, GET, PUT, DELETEメソッドのアクセスを許可する。詳細な制御も可能。
// ----------------------------
//app.use(cors({
// origin: 'https://example.com',
// methods: ['GET', 'POST', 'PUT', 'DELETE'],
// allowedHeaders: ['Content-Type', 'Authorization']
// }));
//app.use(cors());
// ----------------------------
// フォームデータを解析
// ----------------------------
app.use(express.urlencoded({ extended: true })); // フォーム形式(name=value)
app.use(express.json()); // JSON形式({ "key": "value" })
// ------------------------------------
// データベースに接続する関数
// ------------------------------------
function connectDatabase() {}
// ------------------------------------
// データベースを閉じる関数
// ------------------------------------
function closeDatabase(db) {}
// ------------------------------------
// データ読み込み
// ------------------------------------
app.get('/get', (req, res) => {});
// ------------------------------------
// データ書き込み
// ------------------------------------
app.post('/create', (req, res) => {});
// ------------------------------------
// データ削除
// ------------------------------------
app.delete('/delete/:id', (req, res) => {});
// ------------------------------------
// データ更新
// ------------------------------------
app.put('/update/:id', (req, res) => {});
// ------------------------------------
// アプリサーバーが応答することを検査
// ------------------------------------
app.get('/', (req, res) => {
res.send('いえーい');
console.log('いえーい');
});
CORSモジュールをインストールします(未インストールの場合、エラーが表示されます:Error: Cannot find module ‘cors’)
$ npm install corsアプリをテストします。
$ node app-api.js
Node.js待ち受けポート:3003待ち受けポート番号が表示されたら成功です。
ブラウザからアクセスできること
http://ドメイン名:3003/同じホストの別のシェルからアクセスできること
$ curl -X GET http://localhost:3003/6-4. connectDatabase()関数
データベースに接続するコードを記述します。データベースを閉じる関数とペアで呼び出します。
function connectDatabase() {
// MySQLデータベースの接続情報を設定
const db = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME
});
// データベースに接続
db.connect((err) => {
if (err) throw err;
console.log('MySQL接続は成功');
});
return db;
}6-5. closeDatabase(db)関数
接続しているデータベース db を指定して閉じます。
function closeDatabase(db) {
// データベース接続を閉じる
db.end((err) => {
if (err) throw err;
console.log('MySQL接続を閉じました');
});
}6-6. app.get( ‘/get’ ) データ読み込み
CURDにおけるデータ操作の基本形は 1. DB接続 2. クエリ実行 3. DB閉じる。
読み出し[SELECT * FROM テーブル]の場合:
app.get('/get', (req, res) => {
// 1.データベースに接続
const db = connectDatabase();
// 2.データを読み出すクエリ
let sql = 'SELECT * FROM todo';
db.query(sql, (err, results) => {
if (err) throw err;
res.json(results);
// 3.データベースを閉じる
closeDatabase(db);
});
});アプリをテストします。
$ node app-api.js
Node.js待ち受けポート:3003待ち受けポート番号が表示されたら成功です。
ブラウザからアクセスできること
http://ドメイン名:3003/
# 読み出したレコードが表示される
[{"id":1,"flag":"0","plan":"テスト","result":"-"}]同じホストの別のシェルからアクセスできること
$ curl -X GET http://localhost:3003/6-7. APIとポート番号のプロキシ設定
APIアプリのURL 例えば https://servername.com/app や /login などにアクセスしたときに、ポート番号 http://localhost:3000 などに遷移させる設定
$ sudo nano /etc/nginx/sites-available/ドメイン名(例:web.hogehoge.com)
# APIアプリ用に追加
server {
listen 80;
server_name web.funnygeekjp.com;
return 301 https://$host$request_uri; # HTTPをHTTPSにリダイレクト; 404; managed by Certbot
location /user { # webコンテンツのディレクトリ
alias /home/user/www;
index index.html;
}
# アプリ用に追加(Node.js APIへのプロキシ)
location /app {
proxy_pass http://localhost:3000/chat;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_buffering off;
}
location /login {
proxy_pass http://localhost:3000/login;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_buffering off;
}
listen 443 ssl; # SSサーバー証明書の管理 by Certbot
ssl_certificate /etc/letsencrypt/live/web.hogehoge.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/web.hogehoge.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
# アプリ用にプロキシを追加
location /api3001/ {
proxy_pass http://localhost:3001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
location /api3002/ {
proxy_pass http://localhost:3002/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}設定を変更したら nginx を再起動する
$ sudo systemctl restart nginxブラウザで検査する
# ポート番号でアクセス
http://ome.funnygeekjp.com:3007/
# URIでアクセス
https://ome.funnygeekjp.com/api3007/
6-8. バックエンドAPIアプリの永続化
node.js アプリの実行は、[$ node app.js]で起動しています。Linuxサーバーを再起動したときも、同じコマンドでアプリを起動しなければなりません。
これが大事なのですが、アプリがエラーで終了したときは、手動でもう一度コマンド[$ node app.j]で再起動します。
つまり、エラーが発生すると、誰かが手動でアプリを起動するまではアプリを使えないということになります。
ここで pm2(プロセスマネージャー)を使います。pm2は、エラー発生時に自動再起動したり、ログ管理したりできます。
pm2 のインストール
$ npm install -g pm2
インストールできたか検査
$ pm2 -Vpm2でアプリを起動
アプリを起動するコマンド。app.jsはアプリ名を指定します(app-api.jsとか)
$ pm2 start app.jsその他、pm2の使い方
▼実行中のプロセス一覧
$ pm2 list
▼ログを表示
$ pm2 logs
▼プロセスを停止
$ pm2 stop app.js
▼プロセスを削除
$ pm2 delete app.js
▼サーバー再起動したときにアプリを再起動する
$ pm2 start app.js
$ pm2 save
$ pm2 startup
[PM2] Init System found: systemd6-9. app.get( ‘/create’ ) データ書き込み
読み取り[/get]と同様に、書き込み[/create]のコード:
書き込む情報は各自異なるので自分のDatabase設定に合わせること
・テーブル名
・データ項目
・書き込む値(文字列は”や””などコーテーションで囲う。数値はコーテーションなし)
app.post('/create', (req, res) => {
// 1.データベースに接続
const db = connectDatabase();
//plan memo
var inputPlan = req.body.plan;
var inputMemo = req.body.memo;
// 2.データを書き込むクエリ
sql = "INSERT INTO tbl_kano (plan, result, flag) VALUES ('" + inputPlan + "', '" + inputMemo + "', 0)";
db.query(sql, (err, results) => {
if (err) {
console.log('DB書き込みに失敗 X');
throw err;
}
res.json(results);
console.log('DB書き込み成功 O');
});
// 3.データベースを閉じる
closeDatabase(db);
});6-10. app.get( ‘/delete’ ) データ削除
レコードを削除するコード:
削除するテーブルのレコード番号は各自にあわせること
・テーブル名
・削除するレコードの指定条件(id=1などWHERE句)
app.delete('/delete/:id', (req, res) => {
// 1.データベースに接続
const db = connectDatabase();
// 2.URLパラメータから `id` を取得(修正: `req.params.id` を使用)
let myID = req.params.id;
// IDが空ならエラーを返す
if (!myID) {
return res.status(400).json({ message: "削除するIDが指定されていません。" });
}
// SQLクエリを安全に実行
let sql = "DELETE FROM todo WHERE id = ?";
db.query(sql, [myID], (err, results) => {
if (err) {
console.error("DBのレコード削除に失敗:", err);
return res.status(500).json({ message: "データベースエラー" });
}
res.json({ message: `ID[${myID}] を削除しました`, data: results });
console.log(`DBのID[${myID}] を削除成功`);
});
// 3.データベースを閉じる
closeDatabase(db);
});6-11. app.get( ‘/update’ ) データ更新
レコードを書き換えするコード:
どのレコードをどのように書き換えるのか各自のデータ項目にあわせること
・レコードを書き換えする条件
・テーブル、項目名
app.put('/update/:id', (req, res) => {
// 1.データベースに接続
const db = connectDatabase();
// 2.URLパラメータから `id` を取得
let myID = req.params.id;
let myPlan = req.body.plan;
let myResult = req.body.result;
// リクエスト検査
if (!myID) {
console.log("更新するID[%d]が不足しています。", myID);
return res.status(400).json({ message: "更新するIDまたはデータが不足しています。" });
}
// SQLクエリを実行
let sql = "UPDATE tbl_kano SET plan = ?, result = ? WHERE id = ?";
db.query(sql, [myPlan, myResult, myID], (err, results) => {
if (err) {
console.error("レコードの更新に失敗:", err);
return res.status(500).json({ message: "データベースエラー" });
}
res.json({ message: `ID[${myID}] のデータを更新しました`, data: results });
});
console.log("[9]データベース更新を終了しDB閉じます");
// 3.データベースを閉じる
closeDatabase(db);
});6-12. まとめ
バックエンドAPIアプリ(BFF; Backend for Frontend)は完成した。
データベースに、4つのAPIで読み書き・更新削除ができるようになった。
| 動作 | API命名例 | JS関数の命名例, HTTPメソッド | HTMLボタン命名例 |
| Create(レコード追加) | /get | itemAdd(), POST | データ追加 |
| Read(レコード読み取り) | /create | itemRead(), GET | データ読取 |
| Update(レコード更新) | /update | itemUpdate(), PUT | データ更新 |
| Delete(レコード削除) | /delete | ItemDelete(), DELETE | データ削除 |
次は、見た目の楽しいWEBフロントアプリを開発します
以上