express+node.js+sequelizeを試してみる – ServersMan@VPS


前回の「ServersMan@VPSでnode.jsを試してみる」に続いて、今度はnode.jsのSinatra風フレームワークExpressを試してみる。
本当はRuby on Railsを模したExpress on Railwayを試してみたかったけど、まだ機能的に未実装な部分が多かったのでまた今度。
今回はExpressを試してみました。
開発環境はServers@VPSのCentOS 5です。

Expressフレームワークの特徴

本家に書いてあるExpressの特徴をざっくりと、、(間違ってたらごめんなさい)

  1. WEBアプリケーションが簡単に実装できます!
  2. ルーティング設定できます!
  3. コード/テンプレートは分離されてます!
  4. テンプレート用ヘルパーメソッドがあります!
  5. パフォーマンスが良いです!
  6. ビューのレンタリングやパーティアルもサポートしてるぜ!
  7. 環境の切り分けができます。(Railsでいうdevelopmentとproduction)
  8. ジェネレーターもあります!
  9. セッション操作もお手の物!
Expressフレームワークのインストール

コマンドで一発でインストール完了。
あとついでにexpressで必要なejsテンプレートとMySQLのORMであるsequelizeもインストールします。

$ npm install express
$ npm install ejs

sequelizeはgitから最新版を取得してインストールします。(最新版でない日本語対応していないので・・)

git clone https://github.com/ngs/sequelize.git
npm install ./sequelize

骨組みの作成

Expressの骨組みを作成します。
Railsと同じく一発生成コマンドがあります。

$ cd ~/
$ mkdir blog
$ express -t ejs
$ ls
app.js logs pids public test views

Expressを起動してみる

$ node app.js

既定ではポート3000に開きます。ブラウザからアクセスしてみるとようこそと歓迎してくれます。
express + node.js

ログを出力してみる

既定値だとアクセスログが全く表示されないので、表示されるように設定してみる。
app.js 8行目

- var app = module.exports = express.createServer();
+ var app = module.exports = express.createServer(express.logger(),express.bodyParser());

これでサーバーを立ち上げ確認してみると下のような感じでアクセスログが表示される。

$ node app.js
192.168.0.1 – - [Thu, 17 Mar 2011 00:27:25 GMT] “GET / HTTP/1.1″ 200 – “” “Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15 ( .NET CLR 3.0.30729; .NET4.0C)”
192.168.0.1 – - [Thu, 17 Mar 2011 00:27:25 GMT] “GET /stylesheets/style.css HTTP/1.1″ 304 – “http://192.168.0.1:3000/” “Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15 ( .NET CLR 3.0.30729; .NET4.0C)”

またログに任意のメッセージを表示したい場合はconsole.logを使います。

app.get('/', function(req, res){
  console.log("トップページが表示されました。");
  res.render('index', {
    title: 'Express'
  });
});
ルーティング設定のサンプル

ルーティングの設定も簡単にできます。
設定ファイルはapp.js内で行います。

// getメソッドを設定
app.get('/user/:id', function(req, res){
    res.send('user ' + req.params.id);
});
// postメソッドを設定
app.post('/user/:id', function(req, res){
    res.send('user ' + req.params.id);
});
// 正規表現も使えます。
app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res){
    res.send(req.params);
});
フォームで送信した内容を表示する

WEBアプリケーションでよくあるフォーム送信も簡単に実装できます。
テンプレートにフォームを追加します。

<form method="post" action="/chat/<%= id %>">
  <input type="text" name="user[message]" />
  <input type="submit" value="Submit" />
</form>

送信されたフォームデータはreq.bodyで取得することができます。

app.get('/', function(req, res){
  res.render('index', {
    title: 'Express'
  });
});
app.post('/', function(req, res){
  res.send('message: ' + req.body.user.message);
});

ブラウザ上での流れ

sequelizeを使ってMySQLにアクセス&データ挿入してみる

node.jsにはいくつかORMがあるけどsequelizeが評判良さそうだったので使ってみる。
その前にサクッとMysqlのインストールとデータベース作成する。

$ yum install mysql mysql-server mysql-devel
$ /etc/init.d/mysqld start
$ mysql -u root -e ‘CREATE DATABASE ‘express’ DEFAULT CHARACTER SET utf8′
$ mysql -u root express -e ‘CREATE TABLE comments (id int NOT NULL auto_increment, body varchar(400), createdAt datetime, updatedAt datetime, PRIMARY KEY(id));’

MySQL接続からデータ挿入までのコードは以下の通りです。とても簡単です。

// 1. Sequelizeを読みだす
var Sequelize = require("sequelize").Sequelize;
// 2. MySQLに接続
var sequelize = new Sequelize('express', 'root', null, {
  host: "localhost",
  port: 3306
})
// 3. テーブル定義する
var Comment = sequelize.define('comments', {
  body: Sequelize.STRING,
})
// 4. データを挿入する
var comment = new Comment({
  body: 'Hello Express, node.js and sequelize on ServersMan'
});
comment.save(function(){});

ただ、これだとapp.jsを起動する度にコメントが登録されてしまうので、
先程作成したフォーム送信時にコメントされるようにします。

// 先程作成したルーティング内にdoCommentを追加する。
app.post('/', doComment, function(req, res){
  res.send('Sended your comment: ' + req.body.user.message);
});
// コメントをDB挿入するメソッド
function doComment(req, res, next) {
  var comment = new Comment({
    body: req.body.user.message
  });
  comment.save(function(){});
  next();
}
sequelizeを使ってMySQLからデータを取得する

データの挿入ができたので次はデータの取得を行います。
Rails、SinatraやCakePHPを使っている方は予想できるかと思いますが、データの取得にはfindメソッドを使います。

Comment.find(123, function(comment) {
  // ID=123のCommentインスタンスを取得
})

Comment.find({ title: 'aComment' }, function(comment) {
  // title='aComment'のCommentインスタンスを取得
})

Comment.findAll(function(comments) {
  // 全データのCommentインスタンスを配列で取得します。
})

Comment.findAll({where: "name = 'A Comment'"}, function(persons) {
  // name='A Comment'のCommentインスタンスを配列で取得します。
})

ちなみにデータの削除はdestory()を使います。ただ、destroyAll()がないので全データ消す場合には下記のようにする必要があるみたい。

Comment.findAll(function(comments){comments.forEach(function(comment){comment.destroy()})})

データ取得の方法がわかったところで、トップページでコメント一覧を表示してみます。
app.get(‘/’)内をコメント一覧取得するコードを追加します。

app.get('/', function(req, res){
  Comment.findAll(function(comments) {
    res.render('index', {
      title: '一言掲示板',
      comments: comments
    });
  });
});

続いてテンプレートファイル(view/index.ejs)にコメント一覧用コードを追加します。

<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
<form method="post" action="/">
  <input type="text" name="user[message]" />
  <input type="submit" value="Submit" />
</form>
<h2>コメント一覧</h2>
<ul>
<% comments.forEach(function(comment) { %>
  <li><%= comment.body %></li>
<% }) %>
</ul>
ヘルパーメソッドを使ってみる

テンプレートでデータの体裁を整えたい場合などに便利なヘルパーメソッドですが、勿論あります。
app.jsに下記のように記述します。
試しに日付オブジェクトのフォーマット用にヘルパーメソッドを追加してみます。

// Helper Methods
app.helpers({
  at: function(d){ return d.getFullYear() + "/" + d.getMonth() + "/" + d.getDay() + " " + d.getHours() + ":" + d.getMinutes()}
})
<h2>コメント一覧</h2>
<ul>
<% comments.forEach(function(comment) { %>
  <li><%= at(comment.createdAt) %> <%= comment.body %></li>
<% }) %>
</ul>

シンプルな掲示板が完成しました。

感想

当初、サーバーサイドJavascriptは取っつきにくさはあるかと思っていましたが、
試してみると予想以上に簡単で感覚的にコードを記述できるので驚きました。
普段、sinatraを利用している人ならすんなりexpress+node.jsに移行できるのではないでしょうか。
またJavascriptなのでクライアントサイドでも同一言語で記述ができ、処理速度も高速となるとかなり魅力的です。
Ajaxを利用した小規模ウェブアプリケーションを開発する場合、expressより適したフレームワークはないのではないでしょうか。
次はAjaxを使ったexpressアプリを試してみたいと思います。

関連ページ
関連サイト

node.js – http://nodejs.org/
sequelize – http://sequelizejs.com/
express – http://expressjs.com/