Wie füge ich Routenhandler in mehrere Dateien in Express ein?

223

In meiner NodeJS- expressAnwendung habe ich app.jseinige gemeinsame Routen. Dann in einemwf.js möchte ich Datei noch ein paar Routen definieren.

Wie kann ich app.jsandere in der wf.jsDatei definierte Routenhandler erkennen?

Eine einfache Anforderung scheint nicht zu funktionieren.

rafidude
quelle
2
Überprüfen Sie diese Antwort stackoverflow.com/a/38718561/1153703
Bikesh M

Antworten:

399

Wenn Sie möchten die Routen in einer separaten Datei setzen , zum Beispiel routes.js, können Sie die erstellen routes.jsDatei auf diese Weise:

module.exports = function(app){

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

    //other routes..
}

Und dann können Sie es von verlangen app.js dass das app Objekt auf folgende Weise übergeben wird:

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

Schauen Sie sich auch diese Beispiele an

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

BFil
quelle
18
Tatsächlich gibt der Autor (TJ Holowaychuck) einen besseren Ansatz: vimeo.com/56166857
avetisk
Behebt das Routing-Problem für mehrere Dateien, aber auf Funktionen, die in app.js definiert sind, kann in Routen nicht zugegriffen werden.
XIMRX
5
Wenn Sie einige Funktionen benötigen, fügen Sie sie einfach in ein anderes Modul / eine andere Datei ein und fordern Sie sie sowohl von app.js als auch von route.js an
BFil
2
Ich habe alles verstanden, was ich höre, aber benötige ('./ Routen') (App).
ANinJa
6
Es gibt eine bessere Antwort auf diese Frage unten - stackoverflow.com/a/37309212/297939
Dimitry
124

Obwohl dies eine ältere Frage ist, bin ich hier gestolpert und habe nach einer Lösung für ein ähnliches Problem gesucht. Nachdem ich einige der Lösungen hier ausprobiert hatte, ging ich in eine andere Richtung und dachte, ich würde meine Lösung für alle anderen hinzufügen, die hier landen.

In Express 4.x können Sie eine Instanz des Router-Objekts abrufen und eine andere Datei importieren, die mehr Routen enthält. Sie können dies sogar rekursiv tun, sodass Ihre Routen andere Routen importieren, sodass Sie einfach zu wartende URL-Pfade erstellen können. Wenn ich beispielsweise bereits eine separate Routendatei für meinen Endpunkt '/ tests' habe und einen neuen Satz von Routen für '/ tests / automatisiert' hinzufügen möchte, möchte ich diese '/ automatisierten' Routen möglicherweise in eine andere Datei aufteilen Halten Sie meine '/ test'-Datei klein und einfach zu verwalten. Außerdem können Sie Routen logisch nach URL-Pfaden gruppieren, was sehr praktisch sein kann.

Inhalt von ./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);

Inhalt von ./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;

Inhalt von ./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
quelle
2
Dies ist die beste Antwort, sollte ganz oben auf der Liste stehen! Vielen Dank
Kostanos
Kann ich diese Struktur für die Node Js Rest API verwenden?
MSM
@MSMurugan yep u kann mit diesem Muster eine Rest-API erstellen.
ShortRound1911
@ ShortRound1911 Ich erstelle eine Rest-API für dieses Muster und stelle sie auf den plesk-Hosting-Server. Ich erhalte eine Fehlermeldung
MSM
96

Aufbauend auf dem Beispiel von @ShadowCloud konnte ich alle Routen dynamisch in ein Unterverzeichnis aufnehmen.

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

Platzieren Sie dann die Routendateien wie folgt im Routenverzeichnis:

routen / test1.js

module.exports = function(app){

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

    //other routes..
}

Wiederholen Sie dies so oft wie nötig und dann endlich in app.js Platzierung

require('./routes')(app);
Sam Corder
quelle
1
Ich mag diesen Ansatz besser, ermöglicht das Hinzufügen neuer Routen, ohne etwas Spezielles zur Haupt-App-Datei hinzufügen zu müssen.
Jason Miesionczek
3
Schön, dass ich diesen Ansatz auch verwende, mit einer zusätzlichen Überprüfung der Dateierweiterung, da ich Probleme mit SWP-Dateien hatte.
Geekfish
Sie müssen auch nicht readdirSync verwenden, readdir funktioniert einwandfrei.
Paul
5
Ist die Verwendung dieser Methode zum Lesen der Dateien im Verzeichnis mit einem Mehraufwand verbunden, anstatt nur die Routen in Ihrer Datei app.js zu benötigen?
Abadaba
Ich würde auch gerne das gleiche wissen wie @Abadaba. Wann wird dies ausgewertet, wann starten Sie den Server oder bei jeder Anfrage?
Imns
19

Aufbauend auf der vorherigen Antwort ignoriert diese Version von route / index.js alle Dateien, die nicht auf .js (und sich selbst) enden.

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
quelle
Danke dafür. Ich hatte jemanden auf einem Mac, der .DS_StoreDateien hinzufügte , und es brachte alles durcheinander.
JayQuerie.com
19

Geben Sie dies in das vollständige rekursive Routing aller .jsDateien im /routesOrdner ein 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

in /routessetzen Sie whatevername.jsund initialisieren Sie Ihre Routen wie folgt aus :

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' });
    });
}
unendlich1975
quelle
8

Ich versuche diese Antwort mit "express" zu aktualisieren: "^ 4.16.3". Diese Antwort ähnelt 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;

Ich hoffe das kann jemandem helfen. Viel Spaß beim Codieren!

Sukma Saputra
quelle
8

Wenn Sie Express-4.x mit TypeScript und ES6 verwenden, ist dies die beste Vorlage:

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

Viel sauberer als mit varund module.exports.

Gihanchanuka
quelle
5

Eine Änderung an all diesen Antworten:

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

Verwenden Sie einfach einen regulären Ausdruck, um zu filtern, indem Sie jede Datei im Array testen. Es ist nicht rekursiv, filtert jedoch Ordner heraus, die nicht mit .js enden

Reueoverflow
quelle
5

Ich weiß, dass dies eine alte Frage ist, aber ich habe versucht, etwas für mich selbst herauszufinden, und dies ist der Ort, an dem ich gelandet bin. Deshalb wollte ich meine Lösung für ein ähnliches Problem finden, falls jemand anderes die gleichen Probleme hat wie ich. Ich habe. Es gibt ein nettes Knotenmodul namens consign , das viele der hier gezeigten Dateisystem-Aufgaben für Sie erledigt (dh keine readdirSync-Aufgaben). Beispielsweise:

Ich habe eine erholsame API-Anwendung, die ich erstellen möchte, und ich möchte alle Anforderungen, die an '/ api / *' gehen, zur Authentifizierung stellen und alle meine Routen, die in api gehen, in einem eigenen Verzeichnis speichern (Nennen wir es einfach 'api'). Im Hauptteil der App:

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

Innerhalb des Routenverzeichnisses habe ich ein Verzeichnis namens "api" und eine Datei namens api.js. In api.js habe ich einfach:

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;

Alles hat wie erwartet funktioniert. Hoffe das hilft jemandem.

Mike S.
quelle
5

Wenn Sie möchten, dass eine separate .js-Datei Ihre Routen besser organisiert, erstellen Sie einfach eine Variable in der app.jsDatei, die auf ihren Speicherort im Dateisystem verweist:

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

dann,

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

Wo .fooist eine Funktion in Ihrer wf.jsDatei deklariert? z.B

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

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

}
NiallJG
quelle
1
+1. Dies ist der Ansatz, der im offiziellen Beispiel hier gezeigt wird: github.com/strongloop/express/tree/master/examples/…
Matt Browne
1
Funktioniert dies für die gemeinsame Nutzung globaler Funktionen und Variablen unter app.js? Oder müssten Sie sie "weitergeben" wf.foousw., da sie wie bei den anderen vorgestellten Lösungen außerhalb des Anwendungsbereichs liegen? Ich beziehe mich auf den Fall, in dem Sie normalerweise auf gemeinsam genutzte Variablen / Funktionen in wf.foo zugreifen würden, wenn diese nicht von app.js getrennt wären.
David
Ja, wenn Sie die Funktion 'foo' in app.js deklarieren, dann app.get ('/ wf', foo). wird funktionieren
NiallJG
0

Dies ist möglicherweise die beeindruckendste Frage / Antwort (en) zum Stapelüberlauf, die es je gab. Ich liebe die obigen Lösungen von Sam / Brad. Ich dachte, ich würde mich der von mir implementierten asynchronen Version anschließen:

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

Meine Verzeichnisstruktur ist etwas anders. Normalerweise definiere ich Routen in app.js (im Stammverzeichnis des Projekts) durch require-ing './routes'. Folglich überspringe ich den Scheck, index.jsweil ich will einschließen .

BEARBEITEN: Sie können dies auch in eine Funktion einfügen und rekursiv aufrufen (ich habe das Beispiel bearbeitet, um dies zu zeigen), wenn Sie Ihre Routen in Ordnern beliebiger Tiefe verschachteln möchten.

Tandrewnichole
quelle
2
Warum sollten Sie eine aysnc-Version wollen? Vermutlich möchten Sie alle Ihre Routen einrichten, bevor Sie den Verkehr bedienen, oder Sie könnten am Ende einige "falsche" 404 senden.
Joe Abrams
6
Tatsächlich. Ich habe es geschrieben, während ich noch Knoten lernte. Ich stimme im Nachhinein zu, dass es keinen Sinn ergibt.
Tandrewnichols
0

Sie können alle Routenfunktionen in andere Dateien (Module) einfügen und mit der Hauptserverdatei verknüpfen. Fügen Sie in der Express-Hauptdatei eine Funktion hinzu, die das Modul mit dem Server verbindet:

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

und rufen Sie diese Funktion für jedes Routenmodell auf:

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

Definieren Sie in den Moduldateien (z. B. login.js) die Funktionen wie folgt:

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

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

und exportieren Sie es mit der Anforderungsmethode als Schlüssel. Der Wert ist ein Array von Objekten mit jeweils Pfad- und Funktionstasten.

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