Express.js: листинг файлов папки/директории

В Api.Reference есть пример который показывает как разрешить листать все директории внутри public.
app.use(express.directory('public'))
app.use(express.static('public'))
Чтобы лучше понять как это работает можно посмотреть исходник
node_modules/express/node_modules/connect/lib/middleware/directory.js
Возникает вопрос, как быть если я не хочу разрешать листать весь public, а только конкретные папки? Решение может быть таким
// обычный static для public
app.use(express.static(path.join(__dirname, 'public')));
// маунтим роут на папку которую будет обслуживать directory 
// + передаем опции отображения
app.use('/files-list', express.static(path.join(__dirname, 'public', 'files')));
app.use('/files-list', express.directory(path.join(__dirname, 'public', 'files'), {hidden: true, icons: true}));
Или в случае если имя папки на диске совпадает с роутом (тоже самое, только с реальным именем папки для правильных ссылок для загрузки файлов)
app.use('/files', express.directory(path.join(__dirname, 'public', 'files'), {icons: true}));
Нашелся скринкаст на эту тему:

Express.js: .jade template to string

Наверное не нужно объяснять зачем это нужно.

test1.js
exports.test1 = function(req, res){
  res.render('test1', { title: 'test1' }, function(err, body) {
    console.log(body);
  });

  res.send('wooo');
};

test1.jade
div
  = title
p hello world!

Express.js error handing

Поднобные объяснения на английском можно почитать вот тут. Суть в том, что в express.js метод передачи ошибок несколько отличается. Лично мне пока не очень понятно почему так, но инженер который собственно и разрабатывает express.js выбрал такой путь. Наверное с точки зрения идеологии node.js и асинхронного программирования вообще - это правильно (именно передавать ошибки по цепочке, а не ловить их), но мне на данный момент кажется что это несколько кривовато. Если пойму со временем в чем смысл именно такого подхода, то допишу подробнее или исправлю запись.

Обычно в node.js exception-ы ловятся по-человечески, то есть вот так
app.get('/home', function(req, res){
    // ошибка
    throw new Error('error text msg');
});
В случае с express.js схема работы такая
app.get('/home', function(req, res, next){
    // ошибка
    next(new Error('error text msg'));
});
Причем интересно, что в таком простом примере в express.js вполне сработает и первый вариант, но вот пример ниже уже работать не будет. Насколько я понял дело в том что выкинули общий хэндлер ошибок app.error(function(err,...)). Честно говоря причин такого решения я пока не нашел.
app.get('/home', function(req, res, next){
  db.getRow("SELECT * FROM ...", function(err, row){
    throw new Error('error text msg');
  });
});
В этом случае ошибка просвистит мимо и приложение завалится. Православный путь на данный момент — таскать все ошибки по цепочке вручную. Писанины к сожалению получается несколько больше, но вполне вписывается в предусмотренную схему. Неудобно, но пока найдется что-то повеселее - это рабочее решение. Надо будет собраться написать Tj на эту тему.

Как управлять ошибками в express.js сейчас.
./app.js
app.configure(function(){
  //.. здесь вся остальная необходимая конфигурация

  // error 500
  app.use(function(err, req, res, next) {
    res.status(500).render('err500', {
      title: 'ouch.. 500 error',
      err: err
    });
  });
});

// "контроллер" блога
var blog = require('./routes/blog');
// роут на конкретную операцию
app.get('/post/:post_id', blog.blogPost);
./routes/blog
// ... остальное содержимое контроллера
exports.blogPost = function(req, res, next)
{
  // .. проверки что-то ещё
  db.getRow("SEL33ECT b.* \
    FROM blog b \
    WHERE blog_id=?",
    [
      post_id
    ], function(err, post){
      // ловим ошибку
      if (err) {
        return next(err);
      }

      // тут что-то дальше происходит
      // ...
  });
};

Декоратор для mysql - node.js + express.js

dbConfig.js
module.exports = {
  user: 'root',
  password: 'root',
  host: '127.0.0.1',
  database: 'db'
};
db.js
/**
 * decorator for mysql
 */
var mysql = require('mysql'),
    dbConfig = require('./dbConfig'),
    conn = mysql.createConnection(dbConfig);

// standard query
exports.q = function(sql, callee, next){

  if (typeof(callee) != 'object' || !(callee instanceof Array)) {
    calleeSend = [];
  } else {
    calleeSend = callee;
  }

  conn.query(sql, calleeSend, function(err, qres){
    if (err){
      if (typeof(callee) == 'function') {
        return callee(err);
      } else if (typeof(next) == 'function') {
        return next(err);
      } else {
        console.log('Uncaught DB error: ', err);
        console.log('Uncaught error in query: ', sql);
      }
    }

    try {
      if (typeof(callee) == 'function') {
        callee(err, qres);
      } else if (typeof(next) == 'function') {
        next(err, qres);
      }
    } catch(e) {
      next(e);
    }

  });
};

// get row
exports.getRow = function(sql, callee, next){

  if (typeof(callee) != 'object' || !(callee instanceof Array)) {
    calleeSend = [];
  } else {
    calleeSend = callee;
  }

  conn.query(sql, calleeSend, function(err, qres){
    if (err){
      if (typeof(callee) == 'function') {
        return callee(err);
      } else if (typeof(next) == 'function') {
        return next(err);
      } else {
        console.log('Uncaught DB error: ', err);
        console.log('Uncaught error in query: ', sql);
      }
    }

    row = (qres[0]) ? qres[0]: false ;

    try {
      if (typeof(callee) == 'function') {
        callee(err, row);
      } else if (typeof(next) == 'function') {
        next(err, row);
      }
    } catch(e) {
      next(e);
    }

  });

};

// last insert id
exports.lastId = function(next){

  conn.query("SELECT LAST_INSERT_ID() as id", function sres(err, qres){
    var id = (qres[0].id) ? qres[0].id: false ;

    try {
      next(err, id);
    } catch (e) {
      return next(e);
    }

  });
};

// calc found rows
exports.foundRows = function(next){
  conn.query("select found_rows() as cnt", function(err, qres){
    var cnt = (qres[0].cnt) ? qres[0].cnt : false ;

    try {
      next(err, cnt);
    } catch (e) {
      return next(e);
    }
  });
};
Сам mysql — вот этот модуль npm install mysql

Я вообще не уверен что это правильно полностью, надо бы узнать мнение корифеев (где б найти ещё их), но то что оно работает и это вообще возможно и не слишком замороченно - очень радует.

UPD: и правильно думал, ошибка здесь есть - см. Node.js + MySQL FOUND_ROWS()

express.js loading middleware

Искал информацию на эту тему наверное неделю. А все оказалось довольно просто.