How to include route handlers in multiple files in Express? [duplicate] - node.js

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

Related

Express router going inside the same route

I have setup 3 different routes which have their own subroutes
router.use('/items', handleItems(app, router));
router.use('/price', handlePrice(app, router));
router.use('/documents', handleDocuments(app, router));
But when i call http://localhost:3000/api/documents/, it is throwing error as if it is calling functions inside /items routes. How can this happen?
After some more debugging i noticed that call is going inside handleItems handler to the /:id route
function handleItems(app, router) {
router.post('/create-one', itemController.createItem);
router.get('/:id', itemController.getItem);
return router;
}
Please refer to express.Router documentation.
In your example you have:
function handleItems(app, router) {
router.post('/create-one', itemController.createItem);
router.get('/:id', itemController.getItem);
return router;
}
The first parameter is not used, and the second parameter is your router object, so basically, you are registering your routes in the same object and you will end up with something like
/items
/create-one
/:id
/price
What you are looking for is something like:
const { Router } = require("express");
const express = require("express");
const app = express();
app.use("/items", handleItems(Router()));
app.use("/documents", handleDocuments(Router()));
function handleItems(r) {
r.get("/tada", (req, res) => res.json({ msg: `Tada` }));
r.get("/:name", (req, res) => res.json({ msg: `Hello ${req.params.name}` }));
return r;
}
function handleDocuments(r) {
r.get("/", (req, res) => res.json({ msg: "Bonjour" }));
return r;
}
app.listen(3000, () => console.log("πŸš€ Listening"));
In the example above, I registered a "new router" under each path (/items and /documents)
then, I registered each of these at their root paths:
app.use("/items", handleItems(Router()));
With:
function handleItems(r) {
router.post('/create-one', itemController.createItem);
router.get('/:id', itemController.getItem);
return r;
}
I don't know which architecture or what pattern you are using in your application, but if you are not using any you may want to use the following:
Create a routes.js file for each of items, price and documents. For example:
// items.routes.js
const { Router } = require("express");
const router = Router();
router.post('/create-one', itemController.createItem);
router.get('/:id', itemController.getItem);
module.exports = router;
Then in the app.js
const express = require("express");
const app = express();
// load routers
const itemsRoutes = require('./path/to/items.routes.js');
const documentsRoutes = require('./path/to/documents.routes.js');
app.use("/items", itemsRoutes);
app.use("/documents", documentsRoutes);
app.listen(3000, () => console.log("πŸš€ Listening"));
This might be a cleaner and more predictable pattern to work with in many cases

NodeJS unable to get

new to NodeJS and I am trying to get a basic endpoint going. I actually have three different controllers, but one of them will not work. Here is my app.js
var express = require('express');
var app = express();
var db = require('./db');
var config = require('./config/config'); // get config file
global.__root = __dirname + '/';
var ApiController = require(__root + 'auth/ApiController');
app.use('/api/auth', ApiController);
var UserController = require(__root + 'user/UserController');
app.use('/api/users', UserController);
var AuthController = require(__root + 'auth/AuthController');
app.use('/api/auth/users', AuthController);
module.exports = app;
The UserController and AuthController work great but the ApiController:
//this controller handles api token
var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());
router.get('/apiToken') , function(req, res) {
console.log("received request at /apiToken");
res.status(200).send({ token: config.api.token });
};
module.exports = router;
When I try this in Postman you can see:
I know it has to be something really simple because the failing call is nearly identical to the working ones - but I just don't see it.
You have a coding mistake here with a closing paren in the wrong place on this line that happens to not make an interpreter error, but does not execute as intended:
router.get('/apiToken') , function(req, res) {
// here ^
So change this:
router.get('/apiToken') , function(req, res) {
console.log("received request at /apiToken");
res.status(200).send({ token: config.api.token });
};
to this:
router.get('/apiToken', function(req, res) {
console.log("received request at /apiToken");
res.send({ token: config.api.token });
});
FYI, there is no need to do res.status(200) as that is the default status already. You can just use res.send(...) and the status will be set to 200 automatically. You only need to use res.status(xxx) when you want the status to be something other than 200.
Also, running your code though something like jshint will often complain about these types of mistakes that (somewhat by accident) don't throw an interpreter error.

Grouping routes in Express

We can group our routes like this in Laravel:
Route::group("admin", ["middleware" => ["isAdmin"]], function () {
Route::get("/", "AdminController#index");
Route::post("/post", ["middleware" => "csrf", "uses" => "AdminController#index");
});
Basically, all the routes defined in admin group gets the isAdmin middleware and group name automatically. For example, post endpoint listens to admin/post not /post
Is there any way to do the same thing with Express? It would be awesome because my Laravel routes used to be so clean, whereas my Express routes are a bit messy/duplicated.
This is my routes.js on Express at the moment.
app.get("/admin", [passportConfig.isAuthenticated, passportConfig.isAdmin], AdminController.index);
app.post("/admin", [passportConfig.isAuthenticated, passportConfig.isAdmin], AdminController.postIndex);
Thank you.
Since express 4 you can define and compose routers
const app = require('express');
const adminRouter = app.Router();
adminRouter.use(isAdmin);
adminRouter.get('/', admin.index); /* will resolve to /admin */
adminRouter.post('/post', csrf, admin.index); /* will resolve to /admin/post */
app.use('/admin', adminRouter);
Hope that helps!
Just use before of every group you want to do:
app.use('/admin', AdminMiddleware);
app.get('/admin/route1', ...
app.get('/admin/route2', ...
app.use('/user', UserMiddleware);
app.get('/user/route1', ...
app.get('/user/route2', ...
require('express-group-routes');
var app = require('express');
app.group("/api/v1", (router) => {
router.get("/login", loginController.store); // /api/v1/login
});
In case you don't want to add a prefix but still need to group certain routes you can leave the first parameter and go straight for the function:
require('express-group-routes');
var app = require('express');
app.group((router) => {
router.use(middleware);
});
You can use app.use() - https://expressjs.com/en/guide/using-middleware.html#middleware.application
app.use("/admin",[passportConfig.isAuthenticated, passportConfig.isAdmin],AdminController)
// AdminController:
var express = require('express');
var router = express.Router();
router.get('/', AdminController.index);
// etc...
module.exports = router
https://expressjs.com/en/guide/routing.html#express-router
I found some better solution you can follow this method it's working good
Route file route/user.js
var express = require('express')
var router = express.Router()
const authMiddleware = require('../middleware/auth')
express.application.prefix = express.Router.prefix = function(path, middleware, configure) {
configure(router);
this.use(path, middleware, router);
return router;
}
router.prefix('/user', authMiddleware, async function (user) {
user.route('/details').get(function(req, res) {
res.status(201).send('Hello this is my personal details')
}); //also you can use controller method if you have any
});
module.exports = router //make sure you have to import/use this route in main/server js
You can use an npm module
Express group route
here is a code example from npm official module
var app = require('express');
require('express-group-routes');
app.group("/api/v1", (router) => {
router.get("/login", loginController.store); // /api/v1/login
});
Create the group method
export const group = ((callback: (router: Router) => void) => {
const router = express.Router();
callback(router);
return router;
});
Use the group method
import { group } from './relative/path/to/group/method'
const apiRouter = express.Router();
apiRouter.use('/foo', group((router) => {
router.get('/bar', (req, res) => {
res.send('Hello World');
});
}));
This will create a new GET route to "/foo/bar"
I just wrote this module to solve your problem: https://github.com/benjamin658/express-inject-middleware
You can group your middlewares as an array and pass it to the express-inject-middleware...
For example:
import express from 'express';
import { injectMiddleware } from 'express-inject-middleware';
const app = express();
const authMiddleware = (req, res, next) => {
// some auth logic...
};
const fooMiddleware = (req, res, next) => {
// some foo logic
}
const barMiddleware = (req, res, next) => {
// some bar logic
}
app.use(injectMiddleware(
[
authMiddleware,
fooMiddleware,
],
[
// Passing the app.[METHOD] as the parameter.
app.get('/secrets', (req, res, next) => res.send('secrets'));
// Mount barMiddleware itself
app.post('/secrets', barMiddleware, (req, res, next) => res.send('ok'));
],
));
and this is the result:
app.get('/secrets', authMiddleware, fooMiddleware, (req, res, next) => res.send('secrets'));
app.post('/secrets', authMiddleware, fooMiddleware, barMiddleware, (req, res, next) => res.send('ok'));
in express 4 to grouping your routes, you should create some changes :
seperate route files in multiple files like admin and front
pass the router to the divided route files in routes/index.js file
const express = require('express')
require('express-group-routes');
const router = express.Router()
require('./admin/web.router')(router)
require('./front/web.router')(router)
module.exports = router
in each files we can use groups, middlewares and prefixes, like below
const adminPrefix = 'admin'
module.exports = function (router) {
router.use(`\${adminPrefix}`, [ adminMiddleware ]);
router.group(`/${adminPrefix}`, (router) => {
router.get('/', home.index)
});
}

How to separate the routes and models from app.js using NodeJS and Express

I'm creating an app using Node and Express. However, I can see it'll soon become difficult to manage all the routes that are placed inside app.js. I have placed all my models in a subdirectory /models.
Here's my app current structure:
app.js
models
-- products
-- customers
-- ...
public
views
node_modules
In app.js:
var express = require('express'),
routes = require('./routes'),
user = require('./routes/user'),
http = require('http'),
path = require('path'),
EmployeeProvider = require('./models/employeeprovider').EmployeeProvider,
Products = require('./models/products').Products,
Orders = require('./models/orders').Orders,
Customers = require('./models/customers').Customers,
checkAuth = function(req, res, next) {
if (!req.session.user_id) {
res.send('You are not authorized to view this page');
} else {
next();
}
};
var app = express();
Then some configuration like port, views directory, rendering engine, etc.
Further down app.js I've got the routes:
app.get('/product/edit', auth, function(req, res) {
Products.findAll(function(error, prds) {
res.render('product_edit', {
title: 'New Product',
products: prds
});
});
});
At the top I'm assigning the contents of models/products.js to a variable, all works fine. However keeping all routes inside app.js is not ideal. But if I move the routes to routes/product.js and load the Products models:
var prod = require('../models/products.js');
I get an error saying that object has no method findAll.
What am I doing wrong? How can I remove the routes from app.js?
As of express 4.x Router is added to support your case.
A router object is an isolated instance of middleware and routes. You can think of it as a β€œmini-application,” capable only of performing middleware and routing functions. Every Express application has a built-in app router.
Example from expressjs site:
// routes/calendarRouter.js
var express = require('express');
var router = express.Router();
// invoked for any requested passed to this router
router.use(function(req, res, next) {
// .. some logic here .. like any other middleware
next();
});
// will handle any request that ends in /events
// depends on where the router is "use()'d"
router.get('/events', function(req, res, next) {
// ..
});
module.exports = router;
Then in app.js:
// skipping part that sets up app
var calendarRouter = require('./routes/calendarRouter');
// only requests to /calendar/* will be sent to our "router"
app.use('/calendar', calendarRouter);
// rest of logic
Since I don't like repetition, here's what I do:
// app.js
//...
var routes = requireDir('./routes'); // https://www.npmjs.org/package/require-dir
for (var i in routes) app.use('/', routes[i]);
//...
And each file in routes is like:
// routes/someroute.js
var express = require('express');
var router = express.Router();
router.get('/someroute', function(req, res) {
res.render('someview', {});
});
module.exports = router;
This way you can avoid long repetitive lists like this one:
app.use('/' , require('./routes/index'));
app.use('/repetition' , require('./routes/repetition'));
app.use('/is' , require('./routes/is'));
app.use('/so' , require('./routes/so'));
app.use('/damn' , require('./routes/damn'));
app.use('/boring' , require('./routes/boring'));
Edit: these long examples assume each route file contains something like the following:
var router = express.Router();
router.get('/', function(req, res, next) {
// ...
next();
});
module.exports = router;
All of them could be mounted to "root", but what for them is "root", is actually a specific path given to app.use, because you can mount routes into specific paths (this also supports things like specifying the path with a regex, Express is quite neat in regards to what you can do with routing).
I can suggest you this file structure (according to Modular web applications with Node.js and Express from tjholowaychuk):
app.js
modules
users
index.js
model.js
users-api
index.js
static-pages
index.js
user-api and static-pages export expressjs applications, you can easily mount them in app.js.
In users module you can describe some Data Access operations and all methods about manipulating with the User entity (like create, update etc.). Our API module will use all these methods.
And here is sample code of app.js file (without common express stuff, only mounting routes from different modules):
var express = require('express');
var app = express();
// mount all the applications
app.use('/api/v1', require("user-api"));
app.use(require("static-pages"));
app.listen(3000);
To use your modules this way you must start your app like this NODE_PATH=modules node app.js (i put this line to package.json file in scripts section).
Here is sample code of users module:
index.js
User = require("./model");
module.exports = {
get: function(id, callback) {
User.findOne(id, function(err, user) {
callback(err, user);
});
},
create: function(data, callback) {
// do whatever with incoming data here
data = modifyDataInSomeWay(data);
var newUser = new User(data);
newUser.save(function(err, savedUser) {
// some logic here
callback(err, savedUser);
});
}
};
model.js (with Mongoose stuff for example of course!)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var User = new Schema({
firstname : {type: String, required: false},
lastname : {type: String, required: false},
email : {type: String, required: true}
});
module.exports = mongoose.model('user', User);
And example of user-api module (here is the main part of the answer about separating routes and models).
var users = require("users");
var express = require("express");
var app = module.exports = express(); // we export new express app here!
app.post('/users', function(req, res, next) {
// try to use high-level calls here
// if you want something complex just create another special module for this
users.create(req.body, function(err, user) {
if(err) return next(err); // do something on error
res.json(user); // return user json if ok
});
});
And example of static-pages. If you are not going to build a kind of REST interface you may simply create several modules that will render pages only.
var express = require("express");
var app = module.exports = express(); // we export new express app here again!
app.get('/', function(req, res, next) {
res.render('index', {user: req.user});
});
app.get('/about', function(req, res, next) {
// get data somewhere and put it in the template
res.render('about', {data: data});
});
Of course you can do whatever you want with modules. The main idea about expressjs is to use a lot of small apps instead of single one.
About nodejs modules you can read stackoverflow and docs.
Hope this helps.

using object in another js file

I am getting my hands on node.js and I am trying to understand the whole require/exports thing. I have the following main app.js file:
/app.js
var express = require('express'),
http = require('http'),
redis = require('redis'),
routes = require('./routes'),
var app = express(),
client = redis.createClient();
// some more stuff here...
// and my routes
app.get('/', routes.index);
then, I have the routes file:
exports.index = function(req, res){
res.render('index', { title: 'Express' });
};
I can of course use the client object on my app.js file, but how can I use the same object in my routes?
Since req and res are already being passed around by Express, you can attach client to one or both in a custom middleware:
app.use(function (req, res, next) {
req.client = res.client = client;
next();
});
Note that order does matter with middleware, so this will need to be before app.use(app.router);.
But, then you can access the client within any route handlers:
exports.index = function(req, res){
req.client.get(..., function (err, ...) {
res.render('index', { title: 'Express' });
});
};
The easiest way is to export a function from your routes file that takes a client, and returns an object with your routes:
exports = module.exports = function (client) {
return {
index: function (req, res) {
// use client here, as needed
res.render('index', { title: 'Express' });
}
};
};
Then from app.js:
var client = redis.createClient(),
routes = require('./routes')(client);

Resources