node package manager
Stop writing boring code. Discover, share, and reuse within your team. Create a free org »

tier

synchronous express-like middleware using fibext/fibers

Express-like middleware, but the middleware stack is run in sync(like koa, javaee filter).
use fibext or fibers to make the code run in sequence/sync.

simple and with an principle:

  • (mostly) add members other than change the node original request/response api
  • keep consistent with node

Installation

npm install --save tier

Simple usage

var tier = require('tier');
var fibext = require('fibext');
var app = tier();
app.use(function(req, resp, next){//error middleware 
  try{
    next();
  }catch(e){
    resp.statusCode = 500;
    resp.end(e.message);
  }
});
app.use(function(req, resp, next){//logger middleware 
  console.log('before request');
  next();
  console.log('after request');
});
app.use(function(req, resp, next){//used with async code 
  var start = Date.now();
  var fiber = fibext();
  setTimeout(function(){
    fiber.resume();
  }, 1000);
  fiber.wait();
  resp.write('wake up after %s ms', Date.now()-start);
});
 
app.listen(8080);

Use existing express middleware

Generally, tier is compatible with most express middlewares, and you are appreciated to porting the existing express middlewares for easy use

var bodyParser = require('body-parser');
app.use(function(req, resp, next){
  fibext.run(bodyParser.urlencoded(), req, resp);
  fibext.run(bodyParser.json(), req, resp);
  fibext.run(bodyParser.text(), req, resp);
 
  next();
});

More usages

Please refer to the test cases to get more usage examples.

Router

In tier, a router instance is a middleware function too! so, anywhere a middleware can be placed, same as router instance. then you can use nested routers, use router with other middleware functions, and so on.

router has two types of methods, one is router.use, which will match the path pattern just from the beginning, another is router.all|get|post, which should match the whole path pattern. see:

router().use('/a', ...); //will match any url with /a prefix, like /a, /a/b 
router().all('/a', ...); //will only match the url /a, not for /a/b 

Usage examples:

var router = tier.builtin.router;
var r = router();//create a router instance 
r.use(function(req, resp, next){//all passed 
  next();
}).get('/', function(req, resp, next){//only for root url and GET method 
  next();
}).all('/', function(req, resp, next){//only for root url, and any request method 
  next();
});
app.use(r);

router.use|all|get|post([path], middleware, middleware, ...)

  • path: the path pattern. like express, see path-to-regexp. if ignored, it will be attached on the root(/). use req.params to retrieve the named parameter in path pattern.
  • middleware: multiple. can be a function or a router instance.

Supported HTTP methods: get, post, put, delete, head, options, patch, search.

Built-in middlewares

There are some built-in middlewares. each middleware may attach some properties/functions in the req or resp. like:

app.use(tier.builtin.url());
app.use(function(err, req, resp){
  console.log(req.query);
});

router(options)

options has:

  • params: the default params for any request matched in this router. use req.params to access the param.

see #Router for usage.

url()

req.protocol, req.href, req.host, req.hostname, req.port, req.pathname, req.path, req.query, req.search, req.extname

ip(proxy)

req.ip, req.ips

accept()

req.accept is an instance of accepts

redirect(options)

options has:

  • root: the web root url. if resp.redirect with a partial url(like /p/a/t/h), then root will be used to generate full url.

resp.redirect(url[, params])

send()

resp.type(type, charset), resp.send(), resp.json(), resp.sendStatus(code, message), resp.download(filePath, filename) resp.sendFile(filePath, options). see static middleware's options.

static(options)

options:

  • root: required. the root dir of the static files. default process.cwd()
  • maxAge: ms. support ms module
  • index: when request a directory(with trailing slash /), send "index.html" file under the dir
  • directory: when pathname is a directory(without trailing slash /), send 404 by default. set it to redirect to append trailing slash / and then redirect or set it to throw to throw an error
  • headers: object of header name/value pairs

if file not found, an error will be thrown. so wrap it with try...catch block.

session(options)

currently not support secure cookie. options:

  • ttl: the max age(ms) of the session. the expired time will be refreshed when accessing req.session
  • secret: required. used to sign the cookie value
  • name: the cookie name, default tier.sid
  • cookie: default {path: '/', httpOnly: true}

after add this middleware, use req.session to access session object. it has id, destroy() and regenerate() properties. these properties cannot be overwrited.

Coverage

run command npm run test-cov .

=============================== Coverage summary ===============================
Statements   : 97.07% ( 430/443 )
Branches     : 90.37% ( 197/218 )
Functions    : 98.36% ( 60/61 )
Lines        : 97.57% ( 402/412 )
================================================================================

License

Licensed under MIT

Copyright (c) 2015 kiliwalk