node.jsでのRESTサーバ作成

Express.jsを使ってRESTなAPIサーバを作成する方法を調べてみました。

ポイントを箇条書きにします。

各メソッドと、コールする際のHTTPリクエストです。

  • index(GET)
  • new(GET)
  • create(POST)
  • show(GET)
  • edit(GET)
  • update(PUT)
  • destroy(DELETE)

ではExpressのインストールから始めます。

インストール

$ express -e rest-sample
$ cd rest-sample && npm install
$ npm install express-resource --save

app.js

var express = require('express');
var resource = require('express-resource');
// ...
//app.get('/users', user.list);
//app.resource('users', require('./routes/user'));
app.resource('users', require('./routes/user'), { id: 'id' });

routes/user.js

各リクエストで呼ばれるメソッドを定義します。
パラメータはreq.paramsで取得できます。

module.exports = {
   index: function(req, res){
    res.send("index: called as GET method");
  }
  ,new: function(req, res){
    res.send("new: called as GET method");
  }
  ,create: function(req, res){
    res.send("create: called as POST method");
  }
  ,show: function(req, res){
    res.send("show: called as GET method");
  }
  ,edit: function(req, res){
    res.send("edit: called as GET method");
  }
  ,update: function(req, res){
    console.log(req.params);
    res.send("update: called as PUT method");
  }
  ,destroy: function(req, res){
    res.send("destroy: called as DELETE method");
  }
};

$.put()/$.delete()の定義

クライアント側で、$.extend()jQueryを拡張します。$.put()/$.delete()はエラー時のメソッドを渡せるように定義していますが、$.get()/$.post()と同じように、引数を省略しても良いかも知れません。
出力はコンソールなので、画面には何も表示されないです。

// Ajax成功時
var onSuccess = function(data, textStatus, jqXHR) {
	console.group('onSuccess');
	console.log(data);
	console.log(textStatus);
	console.log(jqXHR);
	console.groupEnd();
};
// Ajax失敗時
var onError = function(data, textStatus, jqXHR) {
	console.group('onError');
	console.log(data);
	console.log(textStatus);
	console.log(jqXHR);
	console.groupEnd();
};

// テストケース
var testCase = function() {
	var root = '/users';
	var user_id = 1;
	var calls = {
		get: [
			{endpoint: root},	//index
			{endpoint: root + '/new'},	//new
			{endpoint: root + '/' + user_id},	//show
			{endpoint: root + '/' + user_id + '/edit'}	//edit
		],
		post: [
			{endpoint: root}	//create
		],
		put: [
			{endpoint: root + '/' + user_id},	//update
			{endpoint: root + '/'}	// エラーを起こしてみます
		],
		delete: [
			{endpoint: root + '/' + user_id}	//destroy
		]
	};

	for (var i in calls) {
		for (var j = 0, len = calls[i].length; j < len; j++) {
			if (i === 'get' || i === 'post') {
				$[i](calls[i][j].endpoint, {}, onSuccess, 'text');
			} else {
				$[i](calls[i][j].endpoint, {}, onSuccess, onError, 'text');
			}
		}
	}
};

$(document).ready(function(){
	// jQueryを拡張
	$.extend({
		put: function(url, data, success, error, type) {
			if ($.isFunction(data)) {
				success = data;
				error = success;
				type = error;
				data = {};
			}
			error = error || function() {};
			return $.ajax({
				type: 'PUT',
				url: url,
				data: data,
				success: success,
				error : error,
				cache : false,
				dataType: type
			});
		},
		delete: function(url, data, success, error, type) {
			if ($.isFunction(data)) {
				success = data;
				error = success;
				type = error;
				data = {};
			}
			error = error || function() {};
			return $.ajax({
				type: 'DELETE',
				url: url,
				data: data,
				success: success,
				error : error,
				cache : false,
				dataType: type
			});
		}
	});


	testCase();
});