7

I am using express.js as a webserver and would like an easy way to separate all the "app.get" and "app.post" functions to separate files. For example, if I would like to specify get and post functions for a login page, I would like to have a login.js file in a routes folder that is dynamically loaded (will automatically add all of the files without having to specify each one) when I run node app.js

I have tried this this solution!, but it isn't working for me.

Community
  • 1
  • 1
anonymousfox
  • 769
  • 2
  • 9
  • 19

4 Answers4

18

app.js

var express=require("express");
var app=express();
var fs=require("fs");
var routePath="./routers/"; //add one folder then put your route files there my router folder name is routers
fs.readdirSync(routePath).forEach(function(file) {
    var route=routePath+file;
    require(route)(app);
});
app.listen(9123);

I have put below two routers in that folder

route1.js

module.exports=function(app){
  app.get('/',function(req,res){
     res.send('/ called successfully...');
  });
}

route2.js

module.exports=function(app){
app.get('/upload',function(req,res){
  res.send('/upload called successfully...');
});
}
sachin
  • 13,605
  • 14
  • 42
  • 55
  • @anonymousfox still u fin any difficulty let me know. – sachin May 28 '13 at 06:24
  • Thanks @sachin for the help. I managed to get something working, but it is a little different than the solution that you provided. When I tried passing a relative route "./routers/" into fs.readdirSync, I received an error saying that the directory doesn't exist. If I did the same thing but used __dirname + "/routes", it was able to work. The second problem I encountered was that mac osx was creating .DS_Store files in my routes folder. When the routes were being added, this file was being parsed and it ended up throwing an error. To fix this I added a check to see if there was a .js ext. – anonymousfox May 28 '13 at 19:46
1

Typescript

routes/testroute.ts

import { Router } from 'express';

const router = Router();
router.get('/test',() => {
    // Do your stuffs Here
});



export = router;

index.ts

let app = express() 

const routePath = path.join(__dirname, 'routes');

fs.readdirSync(routePath).forEach(async (filename) => {
    let route = path.join(routePath, filename);
    try {
        const item = await import(route);
        app.use('/api', item.default);
    } catch (error) {
        console.log(error.message);
    }
});

app.listen()

TheBotlyNoob
  • 369
  • 5
  • 16
Aryan Vikash
  • 91
  • 2
  • 6
0

I ended up using a recursive approach to keep the code readable and asynchronous:

// routes     
processRoutePath(__dirname + "/routes");

function processRoutePath(route_path) {
    fs.readdirSync(route_path).forEach(function(file) {
        var filepath = route_path + '/' + file;
        fs.stat(filepath, function(err,stat) {
            if (stat.isDirectory()) {
                processRoutePath(filepath);
            } else {
                console.info('Loading route: ' + filepath);
                require(filepath)(app, passport);
            }
        });
    });
}

This could be made more robust by checking fro correct file extensions etc, but I keep my routes folder clean and did not want the added complexity

-2

With this approach, there is no need to write routes manually. Just setup a directory structure like the URL paths. Example route is at /routes/user/table/table.get.js and API route will be /user/table.

import app from './app'
import fs from 'fs-readdir-recursive'
import each from 'lodash/each'
import nth from 'lodash/nth'
import join from 'lodash/join'
import initial from 'lodash/initial'

const routes = fs(`${__dirname}/routes`)
each(routes, route => {
  let paths = route.split('/')

  // An entity has several HTTP verbs
  let entity = `/api/${join(initial(paths), '/')}`
  // The action contains a HTTP verb
  let action = nth(paths, -1)

  // Remove the last element to correctly apply action
  paths.pop()
  action = `./routes/${join(paths, '/')}/${action.slice(0, -3)}`

  app.use(entity, require(action))
})

Example route:

import { Router } from 'express'
import Table from '@models/table.model'

const routes = Router()

routes.get('/', (req, res, next) => {   
  Table
    .find({user: userIdentifier})
    .select('-user')
    .lean()
    .then(table => res.json(table))
    .catch(error => next(error))
})

module.exports = routes
Julian
  • 1,380
  • 12
  • 28
  • 2
    Lol, lodash just for loading routes. He'll never use it anywhere else in his app, so I think this is a waste of an entire library. –  May 31 '18 at 15:34
  • Exactly as @user6516765 said. It's a waste of memory to just do something that can easily be replicated in vanilla javascript. – Epic Speedy Mar 28 '21 at 15:44
  • lodash is a huge waste of memory and time. Vanilla JavaScript functions such as `.forEach` would be acceptable here – Austin McCalley Dec 14 '21 at 22:32