Express: Как передать приложение-пример маршрутам из другого файла?

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

app.js:

var express   = require('express');
var app       = express.createServer();
var routes    = require('./routes');

var controllers = require('./controllers');
routes.setup(app, controllers);

app.listen(3000, function() {
  console.log('Application is listening on port 3000');
});

routes.js:

exports.setup = function(app, controllers) {

  app.get('/', controllers.index);
  app.get('/posts', controllers.posts.index);
  app.get('/posts/:post', controllers.posts.show);
  // etc.

};

Контроллеры/index.js:

exports.posts = require('./posts');

exports.index = function(req, res) {
  // code
};

Контроллеры/posts.js:

exports.index = function(req, res) {
  // code
};

exports.show = function(req, res) {
  // code
};

Однако эта настройка имеет большую проблему: у меня есть база данных и приложение-экземпляр, который мне нужно передать в действия (контроллеры/*. js). Единственный вариант, о котором я мог думать, - это сделать обе переменные глобальными, что на самом деле не является решением. Я хочу отделить маршруты от действий, потому что у меня много маршрутов и вы хотите их в центральном месте.

Какой лучший способ передать переменные в действия, но отделить действия от маршрутов?

Ответ 1

Node.js поддерживает круговые зависимости.
Использование круговых зависимостей вместо require ('./routes') (app) очищает много кода и делает каждый модуль менее взаимозависим по файлу загрузки:


app.js
var app = module.exports = express(); //now app.js can be required to bring app into any file

//some app/middleware setup, etc, including 
app.use(app.router);

require('./routes'); //module.exports must be defined before this line


маршруты /index.js
var app = require('../app');

app.get('/', function(req, res, next) {
  res.render('index');
});

//require in some other route files...each of which requires app independently
require('./user');
require('./blog');


----- Обновление 04/2014 -----
Express 4.0 установил usecase для определения маршрутов, добавив метод express.router()!
документация - http://expressjs.com/4x/api.html#router

Пример из своего нового генератора:
Написание маршрута:
https://github.com/expressjs/generator/blob/master/templates/js/routes/index.js
Добавление /namespacing в приложение: https://github.com/expressjs/generator/blob/master/templates/js/app.js#L24

По-прежнему существуют возможности для доступа к приложению из других ресурсов, поэтому циклические зависимости все еще являются допустимым решением.

Ответ 3

Как я уже сказал в комментариях, вы можете использовать функцию как module.exports. Функция также является объектом, поэтому вам не нужно менять свой синтаксис.

app.js

var controllers = require('./controllers')({app: app});

controllers.js

module.exports = function(params)
{
    return require('controllers/index')(params);
}

Контроллеры/index.js

function controllers(params)
{
  var app = params.app;

  controllers.posts = require('./posts');

  controllers.index = function(req, res) {
    // code
  };
}

module.exports = controllers;

Ответ 4

Или просто сделайте это:

var app = req.app

внутри промежуточного ПО, которое вы используете для этих маршрутов. Например:

router.use( (req,res,next) => {
    app = req.app;
    next();
});

Ответ 5

Для отдельной базы данных Служба доступа к данным, которая будет работать со всеми БД с простым API и избегать совместного использования.

Разделение маршрутов .setup выглядит как служебные. Вместо этого я предпочел бы размещать маршрутизацию на основе конфигурации. И настройте маршруты в .json или с аннотациями.

Ответ 6

Скажем, что у вас есть папка с именем "contollers".

В вашем приложении app.js вы можете поместить этот код:

console.log("Loading controllers....");
var controllers = {};

var controllers_path = process.cwd() + '/controllers'

fs.readdirSync(controllers_path).forEach(function (file) {
    if (file.indexOf('.js') != -1) {
        controllers[file.split('.')[0]] = require(controllers_path + '/' + file)
    }
});

console.log("Controllers loaded..............[ok]");

... и...

router.get('/ping', controllers.ping.pinging);

в вашем контроллере forlder у вас будет файл "ping.js" с помощью этого кода:

exports.pinging = function(req, res, next){
    console.log("ping ...");
}

И это он....