sails+MongoDBでJSONベースのAPIを作成してみる

先日からAPIサーバをsailsとMongoDBを使って作ってみようとあれこれしてみたのでその際のメモです。

sailsの特徴に

  • 最初からsocket.io(websocket)が利用できる
  • JSONベースのAPIが簡単に作れる

があるのですが、ここでは後者のJSONベースのAPIを作ってみることにして、データストアにMongoDBを使ってみました。*1


準備

sailsのGet Startedページを参考にしつつ、npm及びsailsコマンドが使える状況であれば...

$ sails new testapp
info: Created a new Sails app `testapp`!

testapp というディレクトリが掘られてアプリケーションの雛形が作成されます。

今回はMongoDBへ接続してみるのでそのディレクトリ内でsails-mongoを入れておきます。

$ npm install sails-mongo --save

接続設定

config/connections.js に接続設定を書きます。

既にサンプルの記述はsailsコマンドで出力されているので必要あらばホスト名, ポート番号, 接続用ユーザ名, パスワード, データベース名を書き換えます。

  someMongodbServer: {
    adapter: 'sails-mongo',
    host: 'localhost',
    port: 27017,
    // user: 'username',
    // password: 'password',
    // database: 'your_mongo_db_name_here'
  },

続けて、config/env/development.js に開発環境の場合にモデルから接続するデータベース接続を設定することができるので設定します。 connectionの箇所に上の config/connections.js で定義した接続名を記載。

module.exports = {
  models: {
    connection: 'someMongodbServer'
  }
};

API生成(CRUDできるコントローラ + Modelの生成)

実際にMongoDBに作成されるコレクションに対応するModelとそれをCRUD操作できるコントローラを作成します。

サンプルとしてUserというモデルを作成してみます。sailsコマンドを入力。

$ sails generate api user

info: Created a new model ("User") at api/models/User.js!
info: Created a new controller ("user") at api/controllers/UserController.js!

info: REST API generated @ http://localhost:1337/user
info: and will be available the next time you run `sails lift`.

これで接続設定は完了したのでおもむろにsailsサーバを立ちあげます。新しくMongoDB上にデータベースを作成することになるのでalterを選択してsailsからMongoDB上にデータベースとコレクションを作成してもらいます。

$ sails lift

info: Starting app...

-----------------------------------------------------------------

 Excuse my interruption, but it looks like this app
 does not have a project-wide "migrate" setting configured yet.
 (perhaps this is the first time you're lifting it with models?)

 In short, this setting controls whether/how Sails will attempt to automatically
 rebuild the tables/collections/sets/etc. in your database schema.
 You can read more about the "migrate" setting here:
 http://sailsjs.org/#/documentation/concepts/ORM/model-settings.html?q=migrate

 In a production environment (NODE_ENV==="production") Sails always uses
 migrate:"safe" to protect inadvertent deletion of your data.
 However during development, you have a few other options for convenience:

 1. safe  - never auto-migrate my database(s). I will do it myself (by hand)
 2. alter - auto-migrate, but attempt to keep my existing data (experimental)
 3. drop  - wipe/drop ALL my data and rebuild models every time I lift Sails

What would you like Sails to do?

info: To skip this prompt in the future, set `sails.config.models.migrate`.
info: (conventionally, this is done in `config/models.js`)

warn: ** DO NOT CHOOSE "2" or "3" IF YOU ARE WORKING WITH PRODUCTION DATA **

prompt: ?:  2

 Temporarily using `sails.config.models.migrate="alter"...
 (press CTRL+C to cancel-- continuing lift automatically in 0.5 seconds...)

info:
info:
info:    Sails              <|
info:    v0.10.4             |\
info:                       /|.\
info:                      / || \
info:                    ,'  |'  \
info:                 .-'.-==|/_--'
info:                 `--'-------'
info:    __---___--___---___--___---___--___
info:  ____---___--___---___--___---___--___-__
info:
info: Server lifted in `/Users/usr0600170/pj/testapp`
info: To see your app, visit http://localhost:1337
info: To shut down Sails, press <CTRL> + C at any time.

debug: --------------------------------------------------------
debug: :: Sat Aug 30 2014 15:12:56 GMT+0900 (JST)

debug: Environment : development
debug: Port        : 1337
debug: --------------------------------------------------------

sailsだけにヨットです。

実際にAPIを呼び出してみる。

この時点で先に作成したUserモデルをCRUDすることができるAPIが動作しています。*2

簡単に確認してみるときは、curlでも良いのですがHTTPieが便利なのでこれを使って試してみます。

POSTをすればCreate

$ http -f POST localhost:1337/user name=hideack

HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 145
Content-Type: application/json; charset=utf-8
Date: Sat, 30 Aug 2014 06:15:36 GMT
X-Powered-By: Sails <sailsjs.org>

{
    "createdAt": "2014-08-30T06:15:36.825Z",
    "id": "54016c080a473e0000da6837",
    "name": "hideack",
    "updatedAt": "2014-08-30T06:15:36.825Z"
}

POSTした際に得られたidでGETすればRead

$ http GET localhost:1337/user/54016c080a473e0000da6837

HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 145
Content-Type: application/json; charset=utf-8
Date: Sat, 30 Aug 2014 06:15:54 GMT
X-Powered-By: Sails <sailsjs.org>

{
    "createdAt": "2014-08-30T06:15:36.825Z",
    "id": "54016c080a473e0000da6837",
    "name": "hideack",
    "updatedAt": "2014-08-30T06:15:36.825Z"
}

同様にそのidでDELETEすればDelete

$ http DELETE localhost:1337/user/54016c080a473e0000da6837

HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 145
Content-Type: application/json; charset=utf-8
Date: Sat, 30 Aug 2014 06:19:12 GMT
X-Powered-By: Sails <sailsjs.org>

{
    "createdAt": "2014-08-30T06:15:36.825Z",
    "id": "54016c080a473e0000da6837",
    "name": "hideack",
    "updatedAt": "2014-08-30T06:15:36.825Z"
}

$ http GET localhost:1337/user/54016c080a473e0000da6837

HTTP/1.1 404 Not Found

Connection: keep-alive
Content-Length: 40
Content-Type: text/html; charset=utf-8
Date: Sat, 30 Aug 2014 06:19:20 GMT
X-Powered-By: Sails <sailsjs.org>

No record found with the specified `id`.

sails + MongoDBの構成でシンプルなCRUDするAPIであれば上記の様な手順でサクッとできるので便利ですね。

ただ、これは序章でここからいろいろ試みていくと多々踏み抜いたので追々書いていこうかと思います。

*1:特に指定をしないとJSONベースで格納されるファイルベースのデータストアが利用されます

*2:MongoDBなので...