Express:別のファイルからのルートにアプリインスタンスを渡す方法は?


103

ルートを複数のファイルに分割します。1つのファイルにはすべてのルートが含まれ、もう1つのファイルには対応するアクションが含まれます。私は現在これを達成するための解決策を持っていますが、アクションでそれにアクセスできるように、アプリインスタンスをグローバルにする必要があります。私の現在のセットアップは次のようになります:

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.

};

controllers / index.js:

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

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

controllers / posts.js:

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

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

ただし、この設定には大きな問題があります。アクション(コントローラー/*.js)に渡す必要のあるデータベースインスタンスとアプリインスタンスがあります。私が考えることができる唯一のオプションは、両方の変数をグローバルにすることですが、これは実際には解決策ではありません。たくさんのルートがあり、それらを中央の場所に置きたいので、アクションからルートを分離したいと思います。

アクションに変数を渡すが、アクションをルートから分離する最良の方法は何ですか?


controllers.jsはどのように見えますか?多分あなたはそれを(オブジェクトの代わりに)パラメータを受け取ることができる関数にすることができます。
mihai 2012

require( 'controllers')にはcontrollers / index.jsが必要です。ただし、ルート(routes.jsを参照)でオブジェクトを使用しているため、関数であっても引数を渡すことができないため、関数は機能しません。
クラウディオアルベルティン

回答:


165

使用req.appreq.app.get('somekey')

呼び出しによって作成されたアプリケーション変数express()は、要求オブジェクトと応答オブジェクトに設定されます。

参照:https : //github.com/visionmedia/express/blob/76147c78a15904d4e4e469095a29d1bec9775ab6/lib/express.js#L34-L35


ありがとう。これはapp.set( 'name'、val);で設定された変数にアクセスする最良の方法だと思います。
Pavel Kostenko 2013

4
app.set('somekey', {})app.jsで呼び出すことを忘れないでください
ankitjaininfo '

3
この方法についての私の唯一の不満は、あなたがapp.locals.authorizedを(main.jsではapp.route('/something').get(app.locals.authorized,function(req,res,next){});なく)そのように実行しようとしている場合、reqスコープの外にあるため不可能です。
gabeio 2015年

クエリパラメータごとに異なるパスポート戦略を使用しています。したがって、ミドルウェアでpassport.use( "strategy-name")を設定しようとしています。let passport = req.app、get( 'passport')でのみ、ミドルウェアにパスポートを保存したとしても。別のリクエストセット用に変更されています。なぜそうなのか?
Kartikeya Mishra

これを行うと、reqオブジェクトには、私の場合のredisやdbなどの追加のObjectインスタンスが含まれます。アプリケーションのパフォーマンスに影響しませんか?例:in index.js app.set( 'redis'、redis_client); routes / example.jsでrouter = require( 'express')。Router(); route.get( '/ test'、(req、res、next)=> {conosle.log(req.app.get( 'redis')); return res.send( "// done");})
スーズアーンシュレスタ

101

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


routes / 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は、express.router()メソッドを追加してルートを定義するためのユースケースを修正しました!
ドキュメント-http://expressjs.com/4x/api.html#router

彼らの新しい発電機からの例:
:ルートの書き込み
https://github.com/expressjs/generator/blob/master/templates/js/routes/index.jsを
追加/アプリにそれを名前空間を: https://github.com /expressjs/generator/blob/master/templates/js/app.js#L24

他のリソースからアプリにアクセスするためのユースケースはまだあるため、循環依存関係は依然として有効なソリューションです。


1
「読み込みファイルへの相互依存が少ない」-読み込みファイルの特定のファイルパスに依存しています。これは非常に緊密な結合なので、そうでないふりをしないでください。
カミロマーティン

2
アプリをエクスポートしたapp.js、ルーティングファイルが必要になるので、十分に注意してください(読んで、過去1時間以上に苦労してきたことを行わないでください)。循環呼び出しは実際の混乱を招く可能性があるので、それらどのように機能するかを必ず確認してください!require()
Nateowami、2015

私は正直に言って、req.app.get( 'somekey')の使用に関する@Fengからの回答は、実際に循環依存関係を使用するよりも優れた、よりクリーンなソリューションであると思います。
Claudio Mezzasalma 2016

@Greenアプリが空の場合、appアプリmodule.exportsが定義される前に必要なファイルが必要です。インスタンス化app、設定module.exports、必要なファイルの要求が必要ですがapp 、いずれにしても、循環依存関係の実行は、明白に解決されたアンチパターンです。これを行う必要はもうありません。
Sternは

26

コメントで言ったように、関数をmodule.exportsとして使用できます。関数もオブジェクトなので、構文を変更する必要はありません。

app.js

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

controllers.js

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

controllers / index.js

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

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

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

module.exports = controllers;

関数内でオブジェクトを返すことは問題ありませんか?それとも、例で行うようにメソッドを設定する方が良いですか?
Claudio Albertin、

どちらのアプローチでも大丈夫だと思います。
mihai 2012

メソッドはたくさんあるので、手動ではなくオブジェクトとして設定したいと思います。これはオブジェクトを返すだけで機能しますが、少し平坦な解決策はありませんか?私の実際の方法は2回インデントされます...
クラウディオアルベール

私があなたを理解しているかどうかはわかりませんが、実装をそのcontrollers関数の外に移動できると思います。たとえば、jsfiddle.net
mihaifm

controllers / index.jsはコントローラ変数を返す必要はありませんか?
Yalamber 2013年

5

または単にそれを行います:

var app = req.app

これらのルートに使用しているミドルウェアの内部。そのように:

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

なぜこれが受け入れられない答えであるか誰かが私に言いますか?app.use('my-service', serviceInstance)メインのルーターとreq.app.get('my-service')コントローラーで使用する依存関係については、@ Feng
Felipeが

0

「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 ...");
}

そして、これが…


0
  1. どこにも渡さずにすべてのコントローラーからdbオブジェクトにアクセスできるようにするには、dbオブジェクトをすべてのreqオブジェクトにアタッチするアプリケーションレベルのミドルウェアを作成すると、すべてのコントローラー内でそれにアクセスできます。
// app.js
let db = ...;  // your db object initialized
const contextMiddleware = (req, res, next) => {
  req.db=db;
  next();
};
app.use(contextMiddleware);
  1. 代わりにアプリインスタンスをどこにも渡さないようにするために、アプリがある場所にルートを渡す
// routes.js  It's just a mapping.
exports.routes = [
  ['/', controllers.index],
  ['/posts', controllers.posts.index],
  ['/posts/:post', controllers.posts.show]
];

// app.js
var { routes }    = require('./routes');
routes.forEach(route => app.get(...route));
// You can customize this according to your own needs, like adding post request

最終的なapp.js:

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

let db = ...;  // your db object initialized
const contextMiddleware = (req, res, next) => {
  req.db=db;
  next();
};
app.use(contextMiddleware);

var { routes }    = require('./routes');
routes.forEach(route => app.get(...route));

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

別のバージョン:投稿リクエストの追加など、必要に応じてこれをカスタマイズできます

// routes.js  It's just a mapping.
let get = ({path, callback}) => ({app})=>{
  app.get(path, callback);
}
let post = ({path, callback}) => ({app})=>{
  app.post(path, callback);
}
let someFn = ({path, callback}) => ({app})=>{
  // ...custom logic
  app.get(path, callback);
}
exports.routes = [
  get({path: '/', callback: controllers.index}),
  post({path: '/posts', callback: controllers.posts.index}),
  someFn({path: '/posts/:post', callback: controllers.posts.show}),
];

// app.js
var { routes }    = require('./routes');
routes.forEach(route => route({app}));

-1

すべてのDBをシンプルなAPIで処理し、共有状態を回避するデータベースのデータアウトサービスを分離。

routes.setupを分離すると、オーバーヘッドのように見えます。代わりに構成ベースのルーティングを配置したいと思います。.jsonまたはアノテーションを使用してルートを構成します。


データアクセスサービスとはどういう意味ですか?それはどのように見えますか?
クラウディオアルベルティン

私の実際のroutes.jsファイルははるかに大きく、express-namespacesモジュールを使用しています。ルートをアクションからどのように分離しますか?
Claudio Albertin、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.