¿Cómo incluir manejadores de ruta en múltiples archivos en Express?

223

En mi expressaplicación NodeJS , tengo app.jsalgunas rutas comunes. Luego, en un wf.jsarchivo, me gustaría definir algunas rutas más.

¿Cómo puedo llegar app.jsa reconocer otros controladores de ruta definidos en el wf.jsarchivo?

Un simple requerimiento no parece funcionar.

rafidude
fuente
2
mira

Respuestas:

399

Si desea colocar las rutas en un archivo separado , por ejemplo routes.js, puede crear el routes.jsarchivo de esta manera:

module.exports = function(app){

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

    //other routes..
}

Y luego puede requerir que app.jspase el app objeto de esta manera:

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

Mira también estos ejemplos

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

BFil
fuente
18
En realidad, el autor (TJ Holowaychuck) da un mejor acercamiento: vimeo.com/56166857
avetisk
Resuelve el problema de enrutamiento para varios archivos, pero las funciones definidas en app.js no son accesibles en las rutas.
XIMRX
55
Si necesita algunas funciones, simplemente colóquelas en otro módulo / archivo y solicítelas tanto de app.js como route.js
BFil
2
Entendí todo lo que escuché pero requiero ('./ rutas') (aplicación) este syntex me deja alucinado, ¿alguien puede decirme qué es esto exactamente, o cuál es el uso de esto hasta donde sé su objeto de aplicación "aplicación"?
ANinJa
66
Hay una mejor respuesta a esta pregunta a continuación: stackoverflow.com/a/37309212/297939
Dimitry
124

A pesar de que esta es una pregunta anterior, tropecé aquí buscando una solución a un problema similar. Después de probar algunas de las soluciones aquí, terminé yendo en una dirección diferente y pensé en agregar mi solución para cualquier otra persona que termine aquí.

En express 4.x puede obtener una instancia del objeto enrutador e importar otro archivo que contenga más rutas. Incluso puede hacer esto de forma recursiva para que sus rutas importen otras rutas, lo que le permite crear rutas de URL fáciles de mantener. Por ejemplo, si ya tengo un archivo de ruta separado para mi punto final '/ tests' y quiero agregar un nuevo conjunto de rutas para '/ tests / automatic', es posible que desee dividir estas rutas '/ automatizadas' en otro archivo para mantener mi archivo '/ test' pequeño y fácil de administrar. También le permite agrupar rutas lógicamente por ruta URL, lo que puede ser realmente conveniente.

Contenido 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);

Contenido 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;

Contenido 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
fuente
2
Esta es la mejor respuesta, ¡debe estar en la parte superior de la lista! Gracias
Kostanos
¿Puedo usar esta estructura para Node Js Rest API?
MSM
@MSMurugan sí, puedes construir una API de descanso con este patrón.
ShortRound1911
@ ShortRound1911 Estoy construyendo un descanso api este patrón y lo puse en el servidor de alojamiento plesk, recibo un error
MSM
96

Partiendo del ejemplo de @ShadowCloud pude incluir dinámicamente todas las rutas en un subdirectorio.

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);
    });
}

Luego, coloca los archivos de ruta en el directorio de rutas de esta manera:

rutas / test1.js

module.exports = function(app){

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

    //other routes..
}

Repitiendo eso tantas veces como lo necesitaba y luego finalmente en app.js colocando

require('./routes')(app);
Sam Corder
fuente
1
Me gusta más este enfoque, permite agregar nuevas rutas sin tener que agregar nada específico al archivo principal de la aplicación.
Jason Miesionczek
3
Agradable, también uso este enfoque, con una verificación adicional de la extensión del archivo ya que me he enfrentado a problemas con los archivos swp.
Geekfish
Tampoco tiene que usar readdirSync w / this, readdir funciona bien.
Paul
55
¿Hay alguna sobrecarga al usar este método para leer los archivos en el directorio en lugar de solo requerir las rutas en su archivo app.js?
Abadaba
También me gustaría saber lo mismo que @Abadaba. ¿Cuándo se evalúa esto, cuando inicia el servidor o en cada solicitud?
imns
19

Y construya aún más sobre la respuesta anterior, esta versión de routes / index.js ignorará cualquier archivo que no termine en .js (y en sí mismo)

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
fuente
Gracias por esto. Tenía a alguien en una Mac agregando .DS_Storearchivos y estaba arruinando todo.
JayQuerie.com el
19

Enrutamiento recursivo completo de todos los .jsarchivos dentro de la /routescarpeta, colóquelo 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 /routesponer whatevername.jse inicializar sus rutas de esta manera:

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' });
    });
}
infinito1975
fuente
8

Estoy tratando de actualizar esta respuesta con "express": "^ 4.16.3". Esta respuesta es similar a 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;

Espero que esto pueda ayudar a alguien. ¡Feliz codificación!

Sukma Saputra
fuente
8

Si está utilizando express-4.x con TypeScript y ES6, esta sería la mejor plantilla para usar:

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

Mucho más limpio que usar vary module.exports.

gihanchanuka
fuente
5

Un ajuste a todas estas respuestas:

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

Simplemente use una expresión regular para filtrar mediante la prueba de cada archivo en la matriz. No es recursivo, pero filtrará las carpetas que no terminen en .js

desbordamiento
fuente
5

Sé que esta es una vieja pregunta, pero estaba tratando de resolver algo así para mí y este es el lugar donde terminé, así que quería poner mi solución a un problema similar en caso de que alguien más tenga los mismos problemas que yo ' m teniendo. Hay un buen módulo de nodo llamado consign que hace muchas de las cosas del sistema de archivos que se ven aquí para usted (es decir, no hay cosas readdirSync). Por ejemplo:

Tengo una aplicación de API tranquila que estoy tratando de construir y quiero poner todas las solicitudes que van a '/ api / *' para autenticarme y quiero almacenar todas mis rutas que van en api en su propio directorio (vamos a llamarlo 'api'). En la parte principal de la aplicación:

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

Dentro del directorio de rutas, tengo un directorio llamado "api" y un archivo llamado api.js. En api.js, simplemente tengo:

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;

Todo funcionó como se esperaba. Espero que esto ayude a alguien.

Mike S.
fuente
5

Si desea un archivo .js separado para organizar mejor sus rutas, simplemente cree una variable en el app.jsarchivo que apunte a su ubicación en el sistema de archivos:

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

luego,

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

donde .foose declara alguna función en su wf.jsarchivo. p.ej

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

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

}
NiallJG
fuente
1
+1. Este es el enfoque que se muestra en el ejemplo oficial aquí: github.com/strongloop/express/tree/master/examples/…
Matt Browne
1
¿Funciona para compartir funciones y variables globales en app.js? ¿O tendría que "pasarlos" wf.foo, etc., ya que están fuera del alcance como con las otras soluciones presentadas? Me refiero al caso en el que normalmente accedería a variables / funciones compartidas en wf.foo si no estuviera separado de app.js.
David
sí, si declaras la función 'foo' en app.js, entonces app.get ('/ wf', foo); funcionará
NiallJG
0

Esta es posiblemente la pregunta / respuesta de desbordamiento de pila más impresionante que haya existido. Me encantan las soluciones de Sam / Brad anteriores. Pensé en intervenir con la versión asíncrona que implementé:

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);
                    }
                }
            });
        }
    });
}

La estructura de mi directorio es un poco diferente. Normalmente defino rutas en app.js (en el directorio raíz del proyecto) haciendo require-ing './routes'. En consecuencia, me estoy saltando el cheque en contra index.jsporque quiero incluir ese también.

EDITAR: También puede poner esto en una función y llamarlo de forma recursiva (edité el ejemplo para mostrar esto) si desea anidar sus rutas en carpetas de profundidad arbitraria.

Tandrewnichols
fuente
2
¿Por qué querrías una versión aysnc? Presumiblemente, desea configurar todas sus rutas antes de comenzar a atender el tráfico o de lo contrario podría terminar enviando algunos 404 'falsos'.
Joe Abrams
66
En efecto. Lo escribí mientras seguía aprendiendo nodo. Estoy de acuerdo en retrospectiva que no tiene sentido.
tandrewnichols
0

puede colocar todas las funciones de ruta en otros archivos (módulos) y vincularlo al archivo del servidor principal. en el archivo express principal, agregue una función que vinculará el módulo al servidor:

   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));
   }

y llame a esa función para cada modelo de ruta:

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

en los archivos del módulo (por ejemplo, archivo login.js), defina las funciones como de costumbre:

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

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

y exportarlo con el método de solicitud como una clave y el valor es una matriz de objetos, cada uno con ruta y teclas de función.

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