Nginx/React/Express/MongoDB on Docker の構築 その4 バックエンドサーバ構築 Express on Docker

今回はExpressを使って、バックエンドを構築。
具体的には、Expressを使って、MongoDBを操作するAPIのサーバを構築する。

Expressは小さくて柔軟なwebフレームワーク。
今回は、GET/POST/DELETEに合わせてDBの取得/追加/削除のロジックを構築する。

CentOSのDockerを作成

まずはいつも通りCentOSのDocker作成から

docker run -itd --privileged -p 3000:3000 --name express centos:7 /sbin/init
docker exec -it express /bin/bash

3000番ポートを外部に公開する。

node.jsのインストール

前回と同様にnode.jsのインストール。

yum install -y epel-release
yum install -y nodejs npm

Expressのインストール

ここを参考に、新規アプリケーションを作成していく。

create-react-appでReactのアプリケーションを作成。npm initのとき色々聞かれるけど、空白のままで。

mkdir backend
cd backend/
npm init

続いて、expressのモジュールをインストール

npm install express --save

このコマンドを実行すると、package.jsonの中にexpressのパッケージが追加される。

他に必要なパッケージの追加

  • body-parser
    POSTパラメータをJsonで取得するのに必要

  • mongoose
    MongoDBにつなぐためのモジュール

npm install body-parser --save
npm install mongoose --save

これでpackage.jsonは以下の通り3つのモジュールが追加されている。

{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.18.2",
    "express": "^4.16.3",
    "mongoose": "^5.0.10"
  }
}

動作確認

とりあえず動かしてみる。
チュートリアルのExampleにあるコードをコピーしてindex.jsとして保存。

var express = require('express')
var app = express()

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)

expressの起動

node ./index.js

その後、Dockerの外からホストの3000宛にHTTPリクエストを投げて確認。

$ curl -X GET http://localhost:3000
Hello World!

APIの設計

今回はTODOアプリを想定。

DB

MongoDBにはタスク用のDBが用意されていると想定する。
中身はシンプルで、tododbという名前のDB内にtasksテーブルを作成して、nameのフィールドを持つエントリが増えていく形。

  • tododb
    • tasks
      • name

API

  • GET /api/tasksでタスクリストの取得
  • POST /api/tasksでタスクリストの追加
  • DELETE /api/tasks/:idでタスクリストの削除

Expressの実装

Mongooseを使っているので、この簡単なチュートリアルをコピペして、DBとのやりとりを作る。
index.jsにロジックを追加していく。勉強用なので、MongoDBのアクセス先もべたがき。
アドレスは 172.17.0.4 で、ポートはデフォルトの 27017

var express = require('express');
var bodyParser = require('body-parser');
var mongoose   = require('mongoose');

var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

var router = express.Router();
mongoose.connect('mongodb://172.17.0.4/tododb');

const Task = mongoose.model('Task', { name: String });

router.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

router.route('/tasks')
  .post(function(req, res) {
    var task = new Task();
    task.name = req.body.name;
    task.save(function(err) {
      if (err)
        res.send(err);
      res.json({ message: 'task created' });
    });
  })
  .get(function(req, res) {
    Task.find(function(err, tasks) {
      if (err)
        res.send(err);
      res.json(tasks);
    });
  });

router.route('/tasks/:id')
  .delete(function(req, res) {
     Task.remove({
       _id: req.params.id
     }, function(err, task) {
       if (err)
         res.send(err);
       res.json({ message: 'task deleted' });
     });
  });


app.use('/api', router);
app.listen(3000);

APIサーバの動作確認

上記ファイルを作成するとbackendフォルダ内が以下のようになる。

$ ls -l
total 16
-rw-r--r--.  1 root root 1071 Mar 14 02:08 index.js
drwxr-xr-x. 67 root root 4096 Mar 14 01:39 node_modules
-rw-r--r--.  1 root root  342 Mar 14 01:42 package.json

Expressを起動する

node ./index.js

外部から動作確認。
ちなみに、テスト環境では172.17.0.4のDocker上でMongoDBがデフォルトポート(27017)で待ち受けている前提。

最初は何もタスクがない状態。GETしても何も得られない。

$ curl -X GET http://localhost:3000/api/tasks
[]

新しいタスクを追加してみる。OKのメッセージが返ってきたら取得して確認。

$ curl --data-urlencode "name=task1" -X POST "http://localhost:3000/api/tasks"
{"message":"task created"}

$ curl -X GET http://localhost:3000/api/tasks
[{"_id":"5aa8846f3a07580112286a66","name":"task1","__v":0}]

ちゃんと追加されているので、削除して確認。

$ curl -X DELETE http://localhost:3000/api/tasks/5aa8846f3a07580112286a66
{"message":"task deleted"}

$ curl -X GET http://localhost:3000/api/tasks
[]

おわり

CRUDのUは実装していないけど、APIサーバとしては今は十分。
次はReactからこのAPIサーバにリクエストしてページに表示するところ。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください