Comment inclure des gestionnaires de routes dans plusieurs fichiers dans Express?

223

Dans mon expressapplication NodeJS , j'ai app.jsquelques itinéraires communs. Puis dans unwf.js fichier, je voudrais définir quelques itinéraires supplémentaires.

Comment puis-je app.jsreconnaître d'autres gestionnaires d'itinéraires définis dans le wf.jsfichier?

Un simple besoin ne semble pas fonctionner.

rafidude
la source
2
vérifier cette réponse stackoverflow.com/a/38718561/1153703
Bikesh M

Réponses:

399

Si vous souhaitez placer les routes dans un fichier séparé , par exemple routes.js, vous pouvez créer le routes.jsfichier de cette façon:

module.exports = function(app){

    app.get('/login', function(req, res){
        res.render('login', {
            title: 'Express Login'
        });
    });

    //other routes..
}

Et puis vous pouvez l'exiger de app.jspasser l' app objet de cette façon:

require('./routes')(app);

Jetez également un œil à ces exemples

https://github.com/visionmedia/express/tree/master/examples/route-separation

BFil
la source
18
En fait, l'auteur (TJ Holowaychuck) donne une meilleure approche: vimeo.com/56166857
avetisk
Résout le problème de routage pour plusieurs fichiers, mais les fonctions définies dans app.js ne sont pas accessibles dans les itinéraires.
XIMRX
5
Si vous avez besoin de certaines fonctions, placez-les dans un autre module / fichier et exigez-les de app.js et routes.js
BFil
2
J'ai compris tout entendre mais exiger ('./ routes') (app) ce syntex me souffle, quelqu'un peut-il me dire ce que c'est exactement, ou à quoi ça sert pour autant que je sache son objet d'application qui passe "app"
ANinJa
6
Il y a une meilleure réponse à cette question ci-dessous - stackoverflow.com/a/37309212/297939
Dimitry
124

Même si c'est une question plus ancienne, je suis tombé ici à la recherche d'une solution à un problème similaire. Après avoir essayé certaines des solutions ici, j'ai fini par aller dans une direction différente et j'ai pensé ajouter ma solution à quiconque se retrouverait ici.

Dans express 4.x, vous pouvez obtenir une instance de l'objet routeur et importer un autre fichier contenant plus de routes. Vous pouvez même le faire de manière récursive afin que vos itinéraires importent d'autres itinéraires vous permettant de créer des chemins d'url faciles à entretenir. Par exemple, si j'ai déjà un fichier de route séparé pour mon point de terminaison '/ tests' et que je veux ajouter un nouvel ensemble de routes pour '/ tests / automatisé', je peux vouloir séparer ces routes '/ automatisées' dans un autre fichier pour garder mon fichier '/ test' petit et facile à gérer. Il vous permet également de regrouper logiquement les itinéraires par chemin URL, ce qui peut être très pratique.

Contenu de ./app.js:

var express = require('express'),
    app = express();

var testRoutes = require('./routes/tests');

// Import my test routes into the path '/test'
app.use('/tests', testRoutes);

Contenu de ./routes/tests.js

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

var automatedRoutes = require('./testRoutes/automated');

router
  // Add a binding to handle '/test'
  .get('/', function(){
    // render the /tests view
  })

  // Import my automated routes into the path '/tests/automated'
  // This works because we're already within the '/tests' route so we're simply appending more routes to the '/tests' endpoint
  .use('/automated', automatedRoutes);

module.exports = router;

Contenu de ./routes/testRoutes/automated.js:

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

router
   // Add a binding for '/tests/automated/'
  .get('/', function(){
    // render the /tests/automated view
  })

module.exports = router;
ShortRound1911
la source
2
celui-ci est la meilleure réponse, devrait être en tête de liste! Merci
Kostanos
puis-je utiliser cette structure pour l'API Node Js Rest?
MSM
@MSMurugan yep u peut construire une api de repos avec ce modèle.
ShortRound1911
@ ShortRound1911 Je suis en train de construire une api de repos de ce modèle et mis sur le serveur d'hébergement de plesk, je reçois une erreur
MSM
96

En me basant sur l'exemple de @ShadowCloud, j'ai pu inclure dynamiquement toutes les routes dans un sous-répertoire.

routes / index.js

var fs = require('fs');

module.exports = function(app){
    fs.readdirSync(__dirname).forEach(function(file) {
        if (file == "index.js") return;
        var name = file.substr(0, file.indexOf('.'));
        require('./' + name)(app);
    });
}

Ensuite, en plaçant les fichiers d'itinéraire dans le répertoire routes comme suit:

routes / test1.js

module.exports = function(app){

    app.get('/test1/', function(req, res){
        //...
    });

    //other routes..
}

Répéter cela autant de fois que nécessaire, puis enfin dans app.js en plaçant

require('./routes')(app);
Sam Corder
la source
1
j'aime mieux cette approche, permet d'ajouter de nouvelles routes sans avoir à ajouter quoi que ce soit de spécifique au fichier d'application principal.
Jason Miesionczek du
3
Bien, j'utilise également cette approche, avec une vérification supplémentaire de l'extension de fichier car j'ai rencontré des problèmes avec les fichiers swp.
Geekfish
Vous n'avez pas non plus à utiliser readdirSync avec cela, readdir fonctionne très bien.
Paul
5
Y a-t-il des frais généraux dans l'utilisation de cette méthode pour lire les fichiers dans le répertoire par rapport à la simple exigence des routes dans votre fichier app.js?
Abadaba
J'aimerais également savoir la même chose que @Abadaba. Quand cela est-il évalué, lorsque vous lancez le serveur ou à chaque demande?
imns
19

Et construisez encore plus sur la réponse précédente, cette version de routes / index.js ignorera tous les fichiers ne se terminant pas par .js (et lui-même)

var fs = require('fs');

module.exports = function(app) {
    fs.readdirSync(__dirname).forEach(function(file) {
        if (file === "index.js" || file.substr(file.lastIndexOf('.') + 1) !== 'js')
            return;
        var name = file.substr(0, file.indexOf('.'));
        require('./' + name)(app);
    });
}
Brad Proctor
la source
Merci pour cela. J'avais quelqu'un sur un Mac qui ajoutait des .DS_Storefichiers et ça gâchait tout.
JayQuerie.com
19

Routage récursif complet de tous les .jsfichiers dans le /routesdossier, mettez-le app.js.

// Initialize ALL routes including subfolders
var fs = require('fs');
var path = require('path');

function recursiveRoutes(folderName) {
    fs.readdirSync(folderName).forEach(function(file) {

        var fullName = path.join(folderName, file);
        var stat = fs.lstatSync(fullName);

        if (stat.isDirectory()) {
            recursiveRoutes(fullName);
        } else if (file.toLowerCase().indexOf('.js')) {
            require('./' + fullName)(app);
            console.log("require('" + fullName + "')");
        }
    });
}
recursiveRoutes('routes'); // Initialize it

en /routesvous mettez whatevername.jset initialisez vos itinéraires comme ceci:

module.exports = function(app) {
    app.get('/', function(req, res) {
        res.render('index', { title: 'index' });
    });

    app.get('/contactus', function(req, res) {
        res.render('contactus', { title: 'contactus' });
    });
}
infinity1975
la source
8

J'essaie de mettre à jour cette réponse avec "express": "^ 4.16.3". Cette réponse est similaire à ShortRound1911.

server.js

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const db = require('./src/config/db');
const routes = require('./src/routes');
const port = 3001;

const app = new express();

//...use body-parser
app.use(bodyParser.urlencoded({ extended: true }));

//...fire connection
mongoose.connect(db.url, (err, database) => {
  if (err) return console.log(err);

  //...fire the routes
  app.use('/', routes);

  app.listen(port, () => {
    console.log('we are live on ' + port);
  });
});

/src/routes/index.js

const express = require('express');
const app = express();

const siswaRoute = require('./siswa_route');

app.get('/', (req, res) => {
  res.json({item: 'Welcome ini separated page...'});
})
.use('/siswa', siswaRoute);

module.exports = app;

/src/routes/siswa_route.js

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.json({item: 'Siswa page...'});
});

module.exports = app;

J'espère que cela peut aider quelqu'un. Bon codage!

Sukma Saputra
la source
8

Si vous utilisez express-4.x avec TypeScript et ES6, ce serait le meilleur modèle à utiliser:

src/api/login.ts

import express, { Router, Request, Response } from "express";

const router: Router = express.Router();
// POST /user/signin
router.post('/signin', async (req: Request, res: Response) => {
    try {
        res.send('OK');
    } catch (e) {
        res.status(500).send(e.toString());
    }
});

export default router;

src/app.ts

import express, { Request, Response } from "express";
import compression from "compression";  // compresses requests
import expressValidator from "express-validator";
import bodyParser from "body-parser";
import login from './api/login';

const app = express();

app.use(compression());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());

app.get('/public/hc', (req: Request, res: Response) => {
  res.send('OK');
});

app.use('/user', login);

app.listen(8080, () => {
    console.log("Press CTRL-C to stop\n");
});

Beaucoup plus propre que l'utilisation de varet module.exports.

gihanchanuka
la source
5

Un ajustement à toutes ces réponses:

var routes = fs.readdirSync('routes')
      .filter(function(v){
         return (/.js$/).test(v);
      });

Utilisez simplement une expression rationnelle pour filtrer en testant chaque fichier du tableau. Ce n'est pas récursif, mais il filtrera les dossiers qui ne se terminent pas par .js

regretoverflow
la source
5

Je sais que c'est une vieille question, mais j'essayais de comprendre quelque chose comme pour moi et c'est l'endroit où je me suis retrouvé, alors je voulais mettre ma solution à un problème similaire au cas où quelqu'un d'autre aurait les mêmes problèmes que moi '' m ayant. Il y a un joli module de nœud appelé consign qui fait beaucoup de choses sur le système de fichiers qui sont vues ici pour vous (c'est-à-dire - pas de choses readdirSync). Par exemple:

J'ai une application API reposante que j'essaie de créer et je veux mettre toutes les demandes qui vont dans '/ api / *' pour être authentifié et je veux stocker toutes mes routes qui vont en api dans leur propre répertoire (appelons-le simplement 'api'). Dans la partie principale de l'application:

app.use('/api', [authenticationMiddlewareFunction], require('./routes/api'));

À l'intérieur du répertoire des routes, j'ai un répertoire appelé "api" et un fichier appelé api.js. Dans api.js, j'ai simplement:

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

// get all routes inside the api directory and attach them to the api router
// all of these routes should be behind authorization
consign({cwd: 'routes'})
  .include('api')
  .into(router);

module.exports = router;

Tout a fonctionné comme prévu. J'espère que cela aide quelqu'un.

Mike S.
la source
5

Si vous voulez un fichier .js séparé pour mieux organiser vos itinéraires, créez simplement une variable dans le app.jsfichier pointant vers son emplacement dans le système de fichiers:

var wf = require(./routes/wf);

puis,

app.get('/wf', wf.foo );

.fooest une fonction déclarée dans votre wf.jsfichier. par exemple

// wf.js file 
exports.foo = function(req,res){

          console.log(` request object is ${req}, response object is ${res} `);

}
NiallJG
la source
1
+1. Voici l'approche présentée dans l'exemple officiel ici: github.com/strongloop/express/tree/master/examples/…
Matt Browne
1
Est-ce que cela fonctionne pour partager des fonctions et des variables globales sous app.js? Ou devez-vous les "passer" wf.foo, etc., car ils sont hors de portée comme avec les autres solutions présentées? Je fais référence au cas où normalement vous accéderiez à des variables / fonctions partagées dans wf.foo s'il n'était pas séparé de app.js.
David
oui, si vous déclarez la fonction 'foo' dans app.js, alors app.get ('/ wf', foo); fonctionnera
NiallJG
0

C'est probablement la question / réponse la plus impressionnante de débordement de pile jamais. J'adore les solutions de Sam / Brad ci - dessus. Je pensais que je jouerais avec la version asynchrone que j'ai implémentée:

function loadRoutes(folder){
    if (!folder){
        folder = __dirname + '/routes/';
    }

    fs.readdir(folder, function(err, files){
        var l = files.length;
        for (var i = 0; i < l; i++){
            var file = files[i];
            fs.stat(file, function(err, stat){
                if (stat && stat.isDirectory()){
                    loadRoutes(folder + '/' + file + '/');
                } else {
                    var dot = file.lastIndexOf('.');
                    if (file.substr(dot + 1) === 'js'){
                        var name = file.substr(0, dot);

                        // I'm also passing argv here (from optimist)
                        // so that I can easily enable debugging for all
                        // routes.
                        require(folder + name)(app, argv);
                    }
                }
            });
        }
    });
}

Ma structure de répertoires est un peu différente. Je définis généralement les itinéraires dans app.js (dans le répertoire racine du projet) par require-ing './routes'. Par conséquent, je saute le chèque index.jsparce que je veux également l'inclure.

EDIT: Vous pouvez également mettre ceci dans une fonction et l'appeler récursivement (j'ai édité l'exemple pour le montrer) si vous voulez imbriquer vos routes dans des dossiers de profondeur arbitraire.

tandrewnichols
la source
2
Pourquoi voudriez-vous une version aysnc? Vraisemblablement, vous voulez configurer tous vos itinéraires avant de commencer à servir le trafic, sinon vous pourriez finir par envoyer des «faux» 404.
Joe Abrams
6
En effet. Je l'ai écrit tout en apprenant le nœud. Je reconnais rétrospectivement que cela n'a pas de sens.
tandrewnichols
0

vous pouvez placer toutes les fonctions de routage dans d'autres fichiers (modules) et les lier au fichier serveur principal. dans le fichier express principal, ajoutez une fonction qui liera le module au serveur:

   function link_routes(app, route_collection){
       route_collection['get'].forEach(route => app.get(route.path, route.func));
       route_collection['post'].forEach(route => app.post(route.path, route.func));
       route_collection['delete'].forEach(route => app.delete(route.path, route.func));
       route_collection['put'].forEach(route => app.put(route.path, route.func));
   }

et appelez cette fonction pour chaque modèle d'itinéraire:

link_routes(app, require('./login.js'))

dans les fichiers du module (par exemple - fichier login.js), définissez les fonctions comme d'habitude:

const login_screen = (req, res) => {
    res.sendFile(`${__dirname}/pages/login.html`);
};

const forgot_password = (req, res) => {
    console.log('we will reset the password here')
}

et l'exporter avec la méthode de demande comme clé et la valeur est un tableau d'objets, chacun avec des touches de chemin et de fonction.

module.exports = {
   get: [{path:'/',func:login_screen}, {...} ],
   post: [{path:'/login:forgotPassword', func:forgot_password}]
};   
Tzvika Merchav
la source