node.jsでexpress+sequelizeを使う

node.jsのwebアプリケーションフレームワークであるexpressで、ORMのSequelizeを使ってみる

環境

ArchLinux : バージョンは多分現在の最新
MariaDB : 5.5.32 (MySQLの姉妹実装。archlinuxではこれが公式となる)

node.js : 0.10.9
express : 3.3.4
sequelize : 2.0.0
node-mysql : 2.0.0

expressのインストール

npm install -g express
  • gオプションをつけてグローバルインストールしておく

expressアプリケーションの作成

express ormtest -c css

これでormtestというディレクトリが作られ、中にアプリのガラが作られる

package.jsonにmysqlとsequelizeの追記をしてモジュールをインストールする

{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.3.4",
    "jade": "*",
    "css": "*",
    "mysql": "*",
    "sequelize": "*"
  }
}

ディレクトリ構成はこんな感じに

.
├── app.js
├── node_modules
│   ├── css
│   ├── express
│   ├── jade
│   ├── mysql
│   └── sequelize
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
├── routes
│   ├── index.js
│   └── user.js
└── views
    ├── index.jade
    └── layout.jade

ここで主なファイル/ディレクトリの説明をざっとしておく

app.js: アプリケーションの起動ファイル。アプリケーションで使うミドルウェアや、ルーティングなどを定義する

package.json: 依存モジュールを書くファイル。RailsでいうGemfileに相当

routes: app.jsで設定したルーティングに沿ってアクションを定義するファイルを置くディレクトリ
各ファイルはRailsでいうContorollerに相当する

views: routes以下のファイルで呼び出すHTMLテンプレートを置くディレクトリ
expressではデフォルトのレンダリングエンジンはjadeとなっている

これ以上のexpressの説明は本エントリの主旨から若干外れるので割愛


下記コマンドを実行して起動を確認する

node app.js

ブラウザからhttp://localhost:3000/にアクセスしてexpressの画面が表示されれば成功

Sequelizeを使う

デフォルトではモデル用のディレクトリがないのでディレクトリを作成する

mkdir models

この配下にモデルを書く
今回はシンプルに名前とemailを持つuserモデルを書いてみる

models/user.js

var Sequelize = require('sequelize');
var Seq = new Sequelize('DBNAME', 'DBUSER', 'DBPASS',{
  host: 'localhost',
  port: 3306
});

var User = Seq.define('User', {
    name: Sequelize.STRING,
    email: {
      type: Sequelize.STRING,
      validate: {isEmail: true}
    }
});
//Seq.sync();

exports.User = User;

DBNAME,DBUSER,DBPASSは各環境ごとに設定が必要
Seq.sync()の行を有効にするとDBに定義をしてくれる
本来はここに書くべきではないかも

routes/index.js

/*
 * GET home page.
 */

exports.index = function(req, res){
  var User = require('../models/user').User;
  var new_user = User.build({
    name: "test",
    email: "hoge@example.com"
  });
  new_user.save().success(function(){
    var show_user;
    User.find({
      where: {name: "test"}
    }).success(function(user){
      show_user = {
        name: user.name,
        email: user.email
      };
      res.render('index', { title: 'Express',show_user: show_user });
    });
  });
};

index.jsではmodelを呼び出して新しく値をsaveし、さらに今saveしたデータを引っ張ってきてviewに渡すということをする
ここで、saveのcallbackであるsuccessの中でfindするのがポイント
saveでコールバックを受けずにfindするとsaveが終わる前にfindしてしまってデータが見つからないということが起きる
nodeは非同期でメソッドを実行するのでこのような事が起こる
この事に気づくまで2時間ほど悩みまくったorz
あと、findのsuccessの中でshow_user = userなどとしても正しくデータがとれない
どうやら定義したまんまのUserモデルが返ってくるわけではないらしい


また、saveしたデータは実際にはid,createdAt,updatedAtというカラムが追加され下記の様になっている

MariaDB [DBNAME]> select * from Users;
+------+------------------+----+---------------------+---------------------+
| name | email            | id | createdAt           | updatedAt           |
+------+------------------+----+---------------------+---------------------+
| test | hoge@example.com |  1 | 2013-08-05 13:37:18 | 2013-08-05 13:37:18 |
+------+------------------+----+---------------------+---------------------+


views/index.jade

extends layout

block content
  h1= title
  p Welcome to #{title}
  p #{show_user.name}
  p #{show_user.email}

viewでは持ってきたデータをシンプルに表示してみる

以下のように表示された

f:id:syguer:20130805234734p:plain


Sequelizeでは他にもModelメソッドを定義したり、今回のemailのフィールドで定義したようなバリデータも使えるなどまだまだ機能が豊富なようだ
node.js関連のドキュメントではありがちだが、seauelizeも2.0.0系から変わったのか古いドキュメントのコードをそのまま使っても動かないことが多かった
公式ドキュメントを参考にすることをお勧めする