8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Express, Node.js, RethinkDB, Thinkyを使って作るリアルタイムWebAPI

Last updated at Posted at 2016-09-28

連日似たような投稿ばかりですみません…。

以前、こんな投稿をしました。

この記事は↑の2つを混ぜつつ、実際に動くレベルまで持っていた記録になります。

つまり、RethinkDBへの操作をORMのThinkyでカンタンに行いつつ、Expressを使ってRESTfulなWebAPI化しました。

ソースコードだけみたい、という方はこちらにアップしてあります。

前提条件

RethinkDBをインストールして、ローカルで立ち上げておいてください。
MacOSの方はhomebrewからどうぞ。

$ brew update && brew install rethinkdb
$ rethinkdb # 立ち上げ

セット・アップ

必要なパッケージをインストールします。

$ npm init -y
$ npm install --save express thinky body-parser

package.jsonはだいたいこんな感じ。

{
  "name": "express-thinky-api",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "body-parser": "^1.15.2",
    "express": "^4.14.0",
    "thinky": "^2.3.6"
  }
}

リアルタイムWebAPI作成

ここからは、コードを書いてリアルタイムWebAPIを作っていきます。

Thinky初期化

まずは、thinkyを初期化します。その際に、オブジェクトでセット・アップ情報を渡します。

// ./thinky.js
var thinky = require('thinky')({
  host: 'localhost',
  port: 28015,
  db: 'People'
})

module.exports = thinky

スキーマ定義

まずは、操作対象となるモデルを作成します。
Node.jsからRethinkDBを操作するthinkyをrequireします。

// ./schema.js
const thinky = require('./thinky')
var r = thinky.r

var People = thinky.createModel('People', {
  firstName: String,
  lastName: String,
  coolnessFactor: Number,
  date: { _type: Date, default: r.now() }
})
People.ensureIndex('date')

module.exports = People

Peopleという名前でモデルを生成しました。

Thinkyの使い方については、以下の記事をご覧ください。

node.jsでRethinkDBを扱うためのORM "Thinky" を試してみた

リアルタイム化

RethinkDBの特徴はリアルタイム性です。ここでは、Peopleモデルに対して、リアルタイムロギング機能を付け加えます。

// ./realtime.js
const stringify = (doc) => {
  return JSON.stringify(doc, null, 2)
}

const realtimeLogging = (Model) => {
  Model.changes().then((feed) => {
    feed.each((err, doc) => {
      if (err) {
        console.log(err)
        process.exit(1)
      }
      
      if (doc.isSaved() === false) {
        console.log("The following document was deleted:")
        console.log(stringify(doc))
      } else if (doc.getOldValue() === null) {
        console.log("A new document was inserted:")
        console.log(stringify(doc))
      } else {
        console.log("A document was updated.")
        console.log(stringify(doc.getOldValue()))
        console.log("New value:")
        console.log(stringify(doc))
      }
    })
  }).error((err) => {
    console.log(err)
    process.exit(1)
  })
}

module.exports = realtimeLogging

ちょっと長くなりましたが、ここでやっていることは以下のとおりです。

  • リアルタイム ロギング関数の定義
    • changesメソッドを使って、変更を監視(データの作成・削除・更新がフックになります)
    • 変更のあったドキュメント(いわゆるRow)をログ出力

API作成

APIを作成します。ここでは、ルーティングに応じて呼ばれる関数を定義します。

'use strict'

const thinky = require('./thinky')
const r = thinky.r

const People = require('./schema')

// 一覧取得
exports.list = function (req, res) {
  People.orderBy({ index: r.desc('date') }).run().then((people) => {
    res.json(people)
  }).error((err) => {
    res.json({ message: err })
  })
}

// 作成
exports.add = function (req, res) {
  var person = new People(req.body)
  person.save().then((result) => {
    res.json(result)
  }).error((err) => {
    res.json({ message: err })
  })
}

// 取得
exports.get = function (req, res) {
  People.get(req.params.id).run().then((person) => {
    res.json(person)
  }).error((err) => {
    res.json({ message: err })
  })
}

// 削除
exports.delete = function (req, res) {
  People.get(req.params.id).run().then((person) => {
    person.delete().then((result) => {
      res.json(result)
    }).error((err) => {
      res.json({ message: err })
    })
  }).error((err) => {
    res.json({ message: err })
  })
}

// 更新
exports.update = function (req, res) {
  People.get(req.params.id).run().then((person) => {
    if(req.body.firstName) {
      person.firstName = req.body.firstName
    }
    
    if(req.body.lastName) {
      person.lastName = req.body.lastName
    }
    
    if(req.body.coolnessFactor) {
      person.coolnessFactor = parseInt(req.body.coolnessFactor)
    }
    person.data = r.now()
    
    person.save().then((result) => {
      res.json(result)
    }).error((err) => {
      res.json({ message: err})
    })
  })
}

詳しくはReQL(RethinkDBのクエリ)のAPIをご覧ください。

エントリーポイント作成

エントリーポイントとなるファイルを作成します。コンソールから呼ばれて実行されるファイルですね。

// ./server.js
const express = require('express')
const bodyParser = require('body-parser')

const app = express()

app.use(express.static(__dirname + '/public'))
app.use(bodyParser.json())

// リアルタイムロギング付与
const People = require('./schema')
const realtimeLogging = require('./realtime')
realtimeLogging(People)

// API利用
const api = require('./api')
app.get('/api/people', api.list)
app.get('/api/people/:id', api.get)
app.delete('/api/people/:id', api.delete)
app.put('/api/people/:id', api.update)
app.post('/api/people', api.add)

app.listen(3000)

起動

スクリプトを叩いて、WebAPIを立ち上げましょう。

$ npm start

あるいは、

$ node server.js

 
これで、http://localhost:3000/api/people なんて叩くと一覧が取得できます。
データ操作を行うたびに、コンソールにログが出力されます。

余談

GUIツールが欲しい方は、ReQLProがオススメです。

8
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?