Expressjs - Routes

expressjs

http://www.sitepoint.com/creating-restful-apis-express-4/ - done reading, awesome example of chainable route and using route as a middleware
http://expressjs.com/starter/basic-routing.html - done reading
http://expressjs.com/guide/routing.html

What is a route?

A route is a mapping between a URL or resource to a function that returns that resource or the content of that resource. This function is known as the request handler.

How can we define routes?

Each route is defined using method call corresponding to the appropriate HTTP verb, using a URL pattern as a first parameter (RegExp is also supported), for example:

// for GET method:
app.get('/api/v1/stories/', function(res, req){
  res.send('About Us: ...');
})

// for POST method:
app.post('/api/v1/stories'function(req,res){
  ...
})

DELETE and PUT methods are supported as well. The callbacks that we pass to get() or post() methods are called request handlers, because they take requests (req), process them and write to response (res) objects.

Can we have multiple request handlers with a single route?

Yes. We can have multiple request handlers, hence the name middleware. They accept a third parameter next calling which (next()) will switch the execution flow to the next handler:

app.get('/api/v1/stories/:id', function(req,res, next) {
  //do authorization
  //if not authorized or there is an error 
  // return next(error);
  //if authorized and no errors
  return next();
}), function(req,res, next) {
  //extract id and fetch the object from the database
  //assuming no errors, save story in the request object
  req.story = story;
  return next();
}), function(req,res) {
  //output the result of the database search
  res.send(res.story);
});

Does express support dynamic routes or routes with token?

Yes.

app.get('/article/:id', function(req, res) {
    var entry = blogEngine.getBlogEntry(req.params.id);
    res.render('article',{title:entry.title, blog:entry});
});

Yes. It now includes a token, :id, in the URL. Express allows us to create dynamic URLs that can then map to request arguments. You'll notice that back in the home page, we defined links that looked like this: /article/{{id}}.

We would, in theory, add one route for every blog entry we have, but it is much better to create an abstract route that will match any request of that particular form. To get access to this value, we also add in another piece, the bodyParser line we defined earlier. (This particular feature comes from the Connect framework and actually provides quite a bit of help to you in supporting both query string and form bodies. Almost every Express app will want to include this.)

app.get('/article/:id', function(req, res) {
    var entry = blogEngine.getBlogEntry(req.params.id);
    res.render('article',{title:entry.title, blog:entry});
});

In the above code, 'article' is really 'view/article.html', but because 'view' is the default folder for views, and we've told Express to treat files with .html as template files, we can just shorten it to 'article'. Here's the article.html file:

<h1>{{blog.title}}</h1>
Published: {{blog.published}}
<p/>
{{blog.body}}

How can we create chainable route handlers for a route path?

The app.route() method enables you to create chainable route handlers for a route path. Since the path is specified in a single location, it helps to create modular routes and reduce redundancy and typos. For more information on routes, see Router() documentation.

Here is an example of chained route handlers defined using app.route().

app.route('/book')
  .get(function(req, res) {
    res.send('Get a random book');
  })
  .post(function(req, res) {
    res.send('Add a book');
  })
  .put(function(req, res) {
    res.send('Update the book');
  })

Note that the methods get(), post(), etc. return the same route instance. So, you can chain them together as shown above.

How can we use express.Router to create modular mountable route handlers?

A Router instance is a complete middleware and routing system; for this reason it is often referred to as a "mini-app". The following example creates a router as a module, loads a middleware in it, defines some routes, and mounts it on a path on the main app. Create a router file named birds.js in the app directory, with the following content:

var express = require('express');
var router = express.Router();

// middleware specific to this router
router.use(function timeLog(req, res, next) {
  console.log('Time: ', Date.now());
  next();
})
// define the home page route
router.get('/', function(req, res) {
  res.send('Birds home page');
})
// define the about route
router.get('/about', function(req, res) {
  res.send('About birds');
})

module.exports = router;

Then, load the router module in the app:

var birds = require('./birds');
...
app.use('/birds', birds);

The app will now be able to handle requests to /birds and /birds/about, along with calling the timeLog middleware specific to the route.

Express 4 has a new method called express.Router() which gives us a new router instance. It can be used to define middlewares and routes. The interesting point about Express router is that it’s just like a mini application. You can define middlewares and routes using this router and then just use it in your main app just like any other middleware by calling app.use().

What is app.param?

Parameters are values passed in a query string of a URL of the request. If we didn’t have Express.js or similar library, and had to use just the core Node.js modules, we’d had to extract parameters from HTTP.request object via some require('querystring').parse(url) or require('url').parse(url, true).

Thanks to Connect framework and people at VisionMedia, Express.js already has support for parameters, error handling and many other important features in the form of middlewares. This is how we can plug param middleware in our app:

app.param('id', function(req,res, next, id){
  //do something with id
  //store id or other info in req object
  //call next when done
  next();
});

app.get('/api/v1/stories/:id',function(req,res){
  //param middleware will be execute before and
  //we expect req object already have needed info
  //output something
  res.send(data);
});
app.param('id', function(req,res, next, id){
  req.db.get('stories').findOne({_id:id}, function (e, story){
    if (e) return next(e);
    if (!story) return next(new Error('Nothing is found'));
    req.story = story;
    next();
  });
});

app.get('/api/v1/stories/:id',function(req,res){
  res.send(req.story);
});

How should we organize our routes?

Middleware is flexible. You can use anonymous or named functions, but the best thing is to abstract request handlers into external modules based on the functionality:

var stories = require.('./routes/stories');
var elements = require.('./routes/elements');
var users = require.('./routes/users');
...
app.get('/stories/,stories.find);
app.get('/stories/:storyId/elements/:elementId', elements.find);
app.put('/users/:userId',users.update);

routes/stories.js:

module.exports.find = function(req,res, next) {
};
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License