I have an express server. This is my index.js
let some_parameter = some_value;
const configuredHandler = new Handler(some_parameter);
const server = express();
server
.get("*", configuredHandler.handleRequest)
.post("*", configuredHandler.handleRequest)
.put("*", configuredHandler.handleRequest)
.delete("*", configuredHandler.handleRequest);
I am trying to update the routes if some_parameter to the Handler changes. So it should create a new instance of configuredHandler and the routes should automatically pick the new handler.
Ideally I want to be able to change some_parameter anywhere else in the code.
I am not sure how to structure it for this.
Please help.
What you could do is use something similar to a factory. That factory would create a new middleware every time some_parameter changes and save that middleware for future reference.
Whenever one of your routes is called, express would then refer to the current handler in your factory.
I wrote a simple example:
const express = require('express');
class HandlerFactory {
static currentHandler = (req, res) => res.send('Hello');
static setValue(value) {
this.currentHandler = (req, res) => res.send(value);
}
}
const app = express();
app.post('/change-value', (req, res) => {
HandlerFactory.setValue(req.query.value);
res.send();
});
app.use('/handler', (req, res) => HandlerFactory.currentHandler(req, res));
app.listen(3000);
Just run the app, then test its functionality:
$ curl http://localhost:3000/handler
Hello
$ curl -X POST http://localhost:3000/change-value?value=SecondMessage
$ curl http://localhost:3000/handler
SecondMessage
You can use Router module from expressjs
import { Router } from 'express';
const route1 = new Router();
const route2 = new Router();
const route3 = new Router();
route1.get('/', handler1);
route2.get('/', handler2);
route3.get('/', handler3);
..
..
// similarly define other HTTP routes
const routeMap = {
route1,
route2
route3
}
let some_parameter = 'route1';
const server = express();
const selectedRouter = routerMap[some_parameter];
server.use('*', routerMap[some_parameter]);
I have a sample project on Github that uses similar pattern
This question is very related to this.
In my module I use following:
const express = require('express'),
router = express.Router();
...
module.exports = router;
And I need access to objects in the app.js file. Something like const routes = require(./routes/route.js)(data).
What I tried
module.exports = router(data) But than reqis undefined in the router object.
Made an instance of routein app.js after requiring it. But this results in the same error message. (Like this:
var route = new Route();
route.data = data
Pretty much the same like in the article I mentioned, but I'm not sure what I have to do with the router object. This does not work:
module.exports = router(data){
// all routes
};
Additional information
I normally use routes like this in app.js
const route = require('route.js');
app.use(route);
I am not sure if i understood your question, but if you want to pass data to a module that you require you could do something like this:
const express = require('express'),
router = express.Router();
module.exports = function(data) {
// do stuff with data
router.get('/', (req, res) => res.send(data))
return router;
}
// and then in app.js
const router = require('router.js')(/* pass data to router*/);
app.use(router)
This question already has answers here:
How to separate routes on Node.js and Express 4?
(9 answers)
Closed 1 year ago.
In my NodeJS express application I have app.js that has a few common routes. Then in a wf.js file I would like to define a few more routes.
How can I get app.js to recognize other route handlers defined in wf.js file?
A simple require does not seem to work.
If you want to put the routes in a separate file, for example routes.js, you can create the routes.js file in this way:
module.exports = function(app){
app.get('/login', function(req, res){
res.render('login', {
title: 'Express Login'
});
});
//other routes..
}
And then you can require it from app.js passing the app object in this way:
require('./routes')(app);
Have a look at these examples: https://github.com/visionmedia/express/tree/master/examples/route-separation
In Express 4.x you can get an instance of the router object and import another file that contains more routes. You can even do this recursively so your routes import other routes allowing you to create easy-to-maintain URL paths.
For example, if I have a separate route file for my /tests endpoint already and want to add a new set of routes for /tests/automated I may want to break these /automated routes out into a another file to keep my /test file small and easy to manage. It also lets you logically group routes together by URL path which can be really convenient.
Contents of ./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);
Contents of ./routes/tests.js:
var express = require('express'),
router = express.Router();
var automatedRoutes = require('./testRoutes/automated');
router
// Add a binding to handle '/tests'
.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;
Contents of ./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;
Building on #ShadowCloud 's example I was able to dynamically include all routes in a sub directory.
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);
});
}
Then placing route files in the routes directory like so:
routes/test1.js
module.exports = function(app){
app.get('/test1/', function(req, res){
//...
});
//other routes..
}
Repeating that for as many times as I needed and then finally in app.js placing
require('./routes')(app);
If you're using express-4.x with TypeScript and ES6, this would be the best template to use:
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");
});
Much cleaner than using var and module.exports.
Full recursive routing of all .js files inside /routes folder, put this in 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 /routes you put whatevername.js and initialize your routes like this:
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' });
});
}
And build yet more on the previous answer, this version of routes/index.js will ignore any files not ending in .js (and itself)
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);
});
}
I am trying to update this answer with "express": "^4.16.3". This answer is similar to the one from 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;
If you want a separate .js file to better organize your routes, just create a variable in the app.js file pointing to its location in the filesystem:
var wf = require(./routes/wf);
then,
app.get('/wf', wf.foo );
where .foo is some function declared in your wf.js file. e.g
// wf.js file
exports.foo = function(req,res){
console.log(` request object is ${req}, response object is ${res} `);
}
One tweak to all of these answers:
var routes = fs.readdirSync('routes')
.filter(function(v){
return (/.js$/).test(v);
});
Just use a regex to filter via testing each file in the array. It is not recursive, but it will filter out folders that don't end in .js
I know this is an old question, but I was trying to figure out something like for myself and this is the place I ended up on, so I wanted to put my solution to a similar problem in case someone else has the same issues I'm having. There's a nice node module out there called consign that does a lot of the file system stuff that is seen here for you (ie - no readdirSync stuff). For example:
I have a restful API application I'm trying to build and I want to put all of the requests that go to '/api/*' to be authenticated and I want to store all of my routes that go in api into their own directory (let's just call it 'api'). In the main part of the app:
app.use('/api', [authenticationMiddlewareFunction], require('./routes/api'));
Inside of the routes directory, I have a directory called "api" and a file called api.js. In api.js, I simply have:
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;
Everything worked as expected. Hope this helps someone.
index.js
const express = require("express");
const app = express();
const http = require('http');
const server = http.createServer(app).listen(3000);
const router = (global.router = (express.Router()));
app.use('/books', require('./routes/books'))
app.use('/users', require('./routes/users'))
app.use(router);
routes/users.js
const router = global.router
router.get('/', (req, res) => {
res.jsonp({name: 'John Smith'})
}
module.exports = router
routes/books.js
const router = global.router
router.get('/', (req, res) => {
res.jsonp({name: 'Dreams from My Father by Barack Obama'})
}
module.exports = router
if you have your server running local (http://localhost:3000) then
// Users
curl --request GET 'localhost:3000/users' => {name: 'John Smith'}
// Books
curl --request GET 'localhost:3000/books' => {name: 'Dreams from My Father by Barack Obama'}
I wrote a small plugin for doing this! got sick of writing the same code over and over.
https://www.npmjs.com/package/js-file-req
Hope it helps.
you can put all route functions in other files(modules) , and link it to the main server file.
in the main express file, add a function that will link the module to the server:
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));
}
and call that function for each route model:
link_routes(app, require('./login.js'))
in the module files(for example - login.js file), define the functions as usual:
const login_screen = (req, res) => {
res.sendFile(`${__dirname}/pages/login.html`);
};
const forgot_password = (req, res) => {
console.log('we will reset the password here')
}
and export it with the request method as a key and the value is an array of objects, each with path and function keys.
module.exports = {
get: [{path:'/',func:login_screen}, {...} ],
post: [{path:'/login:forgotPassword', func:forgot_password}]
};
I have a project using NextJS, with Express for server side routing.
lib/routes/getPages
const routes = require('next-routes')();
const getEntries = require('../helpers/getEntries');
module.exports = async (app) => {
const { items: [globalSetings] } = await getEntries({
content_type: 'xxxxxxxx',
include: 1,
limit: 1,
});
routes
.add('/', 'index')
.add(`/${globalSettings.fields.blogSlug}/:slug`, 'blog');
return routes.getRequestHandler(app);
};
server.js
const express = require('express');
const next = require('next');
const getPages = require('./lib/routes/getPages');
const app = next();
app.prepare().then(async () => {
const server = express();
const pageRoutes = await getPages(app);
server.use(pageRoutes);
server.listen(3000);
});
I get slugs for routes (such as the blog section) from my CMS API (which is Contentful in this case). I am wondering how I handle an admin changing a slug in the CMS when the app is already running?
Guessing I will need to restart the app for the new slug/route to work. In this case, will I need to use a webhook and listen for changes from the CMS then somehow restart the app programmatically? This could work but might add overhead. Is there a better way to do it?
You can use a workaround in order to do dynamic routes in express. Here's what I'm using in my Typescript app:
// https://github.com/expressjs/express/issues/2596
let dynamicRouter: express.Router
app.use(
(req, res, next) => dynamicRouter(req, res, next),
)
function loadMyRoutes() {
const newRouter = express.Router()
const newMiddleware = // load my new middleware
newRouter.use(newMiddleware)
dynamicRouter = newRouter
}
You can then call loadMyRoutes() in response to a Contentful webhook.
app.post(`/webhook`, () => {
loadMyRoutes()
})
My app.js looks like this:
app = express();
setup.configure(app);
//...more stuff (e.g. database setup, middleware definition, etc.)...
var api = require('./routes/api');
app.use('/api', api);
module.exports = app;
In the routes/api.js, I then have routes with middleware like this:
router.get('/myroute',
app.sessionMW,
function (req, res, next) {
//...
});
JSLint flags an error because I declare the app variable as global.
If I declare it with var, I get an error in the route because app is undefined. If I require the app in the routes file with var app = require('../app'), I get this error:
Error: Route.get() requires callback functions but got a [object
Undefined]
I would like to properly define the app by doing
var app = express();
But how do I access the app in the routes file?
According to the Express 4.x docs, you can access the app object easily through the request and response objects using req.app & res.app
The Express application object can be referred from the Request object
and the Response object as req.app, and res.app, respectively.
req.app
This property holds a reference to the instance of the Express application that is using the middleware.
res.app
res.app is identical to the req.app property in the Request object.
code-example:
server.js:
var path = require('path');
var express = require('express');
var app = express();
app.set('firends', 'nodejs, python');
var page = require(path.join(
__dirname,
'page'
));
app.use('', page);
app.listen(3000);
page.js:
var express = require('express');
var router = express.Router();
router.get('/test-route', function (req, res) {
var app = req.app; // get app object
res.send('firends are: ' + app.get('firends')); // get firends from app
});
module.exports = router;
Tips:
server.js and page.js are in the same folder.
run with command: node server.js
visit with url: http://127.0.0.1:3000/test-route
You can just pass your app object in your routes/api.js file:
app.js
var api = require('./routes/api')(app); // pass 'app'
routes/api.js
module.exports = function(app) {
...
router.get('/myroute', app.sessionMW, function (req, res, next) { //... });
...
})