RESTful forms in express

Express by default is quite agnostic about application structure. I’ve been working on a personal project where listing routes in express quickly got bloated and cumbersome. Recently, I plugged in express-resource for resourceful routing. This reduced a lot of the explicit url routing to implicit REST actions.

Basically in a RESTful architecture, CRUD operations (Create, read, update, delete) are implemented for resources. HTTP has request methods such as GET, POST, PUT, DELETE.

Using these request methods we can implement REST actions. As an example, lets define a forum resource:

HTTP    | URL                 |  Action 
---------------------------------------
GET     /forums              ->  index
GET     /forums/new          ->  new
POST    /forums              ->  create
GET     /forums/:forum       ->  show
GET     /forums/:forum/edit  ->  edit
PUT     /forums/:forum       ->  update
DELETE  /forums/:forum       ->  destroy

As a user browses to the above urls, we want the resource controller to handle the associated action. To implement this scheme we can simply require express-resource in our project:

var Resource = require('express-resource')

This enables app.resource which maps our url scheme to the above actions:

app.resource('forums', require('./controllers/forum'));

Define controllers/forum.js:

exports.index = function(req, res){
  res.send('forum index');
};

exports.new = function(req, res){
  res.send('new forum');
};

exports.create = function(req, res){
  res.send('create forum');
};

exports.show = function(req, res){
  res.send('show forum ' + req.forum.title);
};

exports.edit = function(req, res){
  res.send('edit forum ' + req.forum.title);
};

exports.update = function(req, res){
  res.send('update forum ' + req.forum.title);
};

exports.destroy = function(req, res){
  res.send('destroy forum ' + req.forum.title);
};

Now we can browse to http://localhost:3000/forums which triggers forum.index(req, res)

This makes routing much easier and consistent since you basically replace

app.get('/forums', Forum.index)
app.get('/forums/new', Forum.new)
app.get('/forums/:id', Forum.show)
app.post('/forums', Forum.create)
app.put('/forums/:id', Forum.update)
// etc..

with a one-liner:

app.resource('forums', require('./controllers/forum'));

Caveat: HTML forms do not support PUT or DELETE methods, only GET and POST. One way to get around this is to use POST and add a hidden value to specify if its PUT or DELETE. To support this, enable methodOverride() in your express stack:

app.use(express.methodOverride());

Then on the client side, we’ll emulate a POST form by creating a typical POST form with a hidden _method var. We’ll set this to put so the server will automatically handle it

<form> ...
  <input type="hidden" name="_method" value="put" />
</form>

Then you can use app.put() or app.del() freely! Since express-resource uses HTTP PUT and DELETE for the update and delete actions, you can just tag forms with _method to emulate PUT and DELETE requests.


comments powered by Disqus