Node.js+Express+MongoDBでREST APIをつくる


# Node.js

1.http://nodejs.org からNode.jsをインストールする

2.マニュアル
https://nodejs.org/api/

# Express

## 動かす

http://expressjs.com/en/starter/generator.html

に従う。以下、簡単な手順。


1.インストール

```
$ npm install express-generator -g
```

2.Express application generator実行


```
$ express restapi; cd restapi; npm install
```

3.動かす

Mac

```
$ DEBUG=restapi:* npm start
```

Windows

```
> set DEBUG=restapi:* & npm start
```

4.ブラウザで確認する
http://localhost:3000

5.マニュアル
http://expressjs.com/4x/api.html

## 変更したときにオートリロードするようにnode-devをいれる

1.インストール

```
$ npm install -g node-dev
```

2.動かす

```
$ node-dev bin/www
```

# MongoDB

## インストール

以下からインストール。
http://www.mongodb.org/

macの場合はbrewからインストールするといいかも。

```
brew install mongodb
```

brewでインストールすると、次のメッセージがでるので、lnとlaunchctlコマンドをうつ。
（または、mongodコマンド）

```
To have launchd start mongodb at login:
    ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents
Then to load mongodb now:
    launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
Or, if you don't want/need launchctl, you can just run:
    mongod --config /usr/local/etc/mongod.conf
```

## コマンド操作

1.起動

```
mongo
```

2.以下のコマンドで操作（詳細は公式サイトで確認）

https://docs.mongodb.org/manual/core/crud-introduction/


コマンド|説明
---|---
show dbs|データベース一覧表示
use [db_name]|データベース切り替え。ないときは最初の挿入時に作成される。
db|現在のデータベース表示
help|ヘルプ
db.getCollectionNames()|すべてのコレクションのリスト表示
db.[collection_name]|コレクション
db.[collection_name].insert({key:value})|挿入
db.[collection_name].find()|検索（SELECT）
db.[collection_name].find({key:value})|条件検索
db.[collection_name].update({key1:value1}, {key2:value2})|キーkey1の値がvalue1であるドキュメントのキーkey2の値をvalue2に更新
db.[collection_name].update({key1:value1}, {$set:{key2:value2}})|キーkey1の値がvalue1であるドキュメントのキーkey2の値をvalue2に更新（値がないときは追加）
db.[collection_name].remove({key:value})|条件削除

3.終了

```
exit
```

## Node+Expressから接続

### MongoDB Driverのインストール

1.インストール

```
npm install --save mongodb
```

2.マニュアル

インターネットの情報は新旧混ざってるので、バージョンには注意。

http://mongodb.github.io/node-mongodb-native/2.1/api/

## mongodb操作用のmongo.jsを追加

ここの書き方は、バージョンに依存する部分が多く、インターネットには新旧の情報が混じっているので注意。
ここでは、2.1のドキュメントに準拠して書いている。
http://mongodb.github.io/node-mongodb-native/2.1/api

```mongo.js
/**
 * node-mongodbのドキュメント
 * http://mongodb.github.io/node-mongodb-native/2.1/
 */
var db;
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/Sakepedia';

// Use connect method to connect to the Server
MongoClient.connect(url, function(err, mongodb) {
  assert.equal(null, err);
  console.log("Connected correctly to server");
  db = mongodb;
});

var collection = function( name ) {
  return db.collection( name );
}

module.exports = collection;
```

# ルーティング

1.app.jsを変更
 
```app.js
(前略)

// var routes = require('./routes/index');
// var users = require('./routes/users');
var restapi = require( './routes/restapi' );

(中略)

// app.use('/', routes);
// app.use('/users', users);
app.use( '/api', restapi );

(後略)
```

2.restapi.jsの追加

* routes.jsをシンプルにしたいので、`var collection = require( '../mongo' );`部分でMongoDB用ファイルは別ファイルにしている
* Cross Origin制約のために`router.all`ですべてのメソッドにheaderを設定している（もちろん他のドメインに使わせたくない場合は不要）
* パスの`:id`部分はパラメーターとして`request.params.id`のように扱える
* idを扱うために、`var ObjectID = require('mongodb').ObjectID;`部分でObjectIDをインポートしている

```routes/restapi.js
var express = require( 'express' );
var router = express.Router();
var ObjectID = require('mongodb').ObjectID;
// MongoDB用ファイルを指定
var collection = require( '../mongo' );
var COL = 'restapi';

// For Cross Origin
router.all( '/*', function ( req, res, next ) {
    res.contentType( 'json' );
    res.header( 'Access-Control-Allow-Origin', '*' );
    next();
} );

// GET find
router.get( '/', function ( req, res ) {
  collection(COL).find().toArray(function(err, docs){
    res.send(docs);
  })
} );

// GET find :id
router.get( '/:id', function ( req, res ) {
  collection(COL).findOne( { _id: new ObjectID( req.params.id ) }, {}, function(err, r){
    res.send( r );
  } );
} );


// POST insert data
router.post( '/', function ( req, res ) {
  collection(COL).insertOne( req.body ).then(function(r) {
    res.send( r );
  });
} );

// PUT update data
router.put( '/:id', function ( req, res ) {
  collection(COL).findOneAndUpdate( { _id: new ObjectID( req.params.id ) }, req.body, {}, function(err, r){
    res.send( r );
  } );
} );

// DELETE remove data
router.delete( '/:id', function ( req, res ) {
  collection(COL).findOneAndDelete( { _id: new ObjectID( req.params.id ) }, {}, function(err, r){
    res.send( r );
  } );
} );

module.exports = router;
```

3.自動生成された不要なファイルを削除。

```
$ rm routes/index.js; rm routes/users.js; rm views/*
```

# 確認

```
$ curl http://localhost:3000/api -X POST -d "name=name1"
$ curl http://localhost:3000/api -X POST -d "name=name2"
$ curl http://localhost:3000/api
$ curl http://localhost:3000/api/xxxxxxxxxxxxxxxxxxxxxxxx
$ curl http://localhost:3000/api/xxxxxxxxxxxxxxxxxxxxxxxx -X PUT -d "name=update"
$ curl http://localhost:3000/api
$ curl http://localhost:3000/api/xxxxxxxxxxxxxxxxxxxxxxxx -X DELETE
$ curl http://localhost:3000/api
```

# これまでの内容をgitにcommit

.gitignore作成（[gitignore](http://www.gitignore.io)で作るとよい）。

```.gitignore

# Created by https://www.gitignore.io/api/node

### Node ###
# Logs
logs
*.log
npm-debug.log*

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directory
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
node_modules

# Optional npm cache directory
.npm

# Optional REPL history
.node_repl_history
```

gitにcommit

```
$ git init
$ git add .
$ git commit -m "first commit"
```

# Herokuへデプロイ

https://devcenter.heroku.com/articles/getting-started-with-nodejs#introduction

に従う。以下、簡単な手順。

1.Herokuのアカウント作成とHeroku Toolbeltのインストール
略

2.Herokuにプロジェクト作成

`ita-restapi`部分（名前）は使われているとエラーになるので注意。

```
$ heroku login
$ heroku create ita-restapi
```

アプリのURLとGitのURLが表示される。

```
https://ita-restapi.herokuapp.com/ | https://git.heroku.com/ita-restapi.git
```

3.Procfile作成

```Procfile
web: DEBUG=restapi:* npm start
```

4.mongolabの作成

https://devcenter.heroku.com/articles/mongolab

```
$ heroku addons:create mongolab --app ita-restapi
$ heroku config --app ita-restapi | grep MONGOLAB_URI
```

mongolalのURIが表示される

```
MONGOLAB_URI: mongodb://heroku_xxxxxxxx:yyyyyyyyyyyyyyyyyyyyyyyyyy@zzzzzzzz.mongolab.com:37185/heroku_xxxxxxxx
```

5.mongo.jsのurlを変更する

Heroku用にブランチをきる。

```
$ git checkout -b heroku
```

mongo.jsを変更する。

```mongo.js
(前略)
// Connection URL
//var url = 'mongodb://localhost:27017/restapi';
var url = 'mongodb://heroku_xxxxxxxx:yyyyyyyyyyyyyyyyyyyyyyyyyy@zzzzzzzz.mongolab.com:37185/heroku_xxxxxxxx';
(後略)
```

コミット

```
$ git add .
$ git commit -m "Change mongodb url for heroku"
```

6.Herokuにデプロイ

```
$ git remote add heroku https://git.heroku.com/ita-restapi.git
$ git push heroku heroku:master
```

# 完成品(master)

https://github.com/itagakishintaro/restapi