Search code examples
node.jsexpressmoduletypescriptcommonjs

typescript node.js express routes separated files best practices


using Express in a Node project along with Typescript what would be the "best practices" for express.Router.

example directory structure

|directory_name
  ---server.js
  |--node_modules
  |--routes
     ---index.ts
     |--admin
        ---admin.ts
     |--products
        ---products.ts
     |--authentication
        ---authentication.ts

so inside index.ts it would encapsulate and manage all the sub-routers

//admin.ts (nested inside of index.ts)
import * as express from "express";

export = (() => {
    
    let router = express.Router();
          
    router.get('/admin', (req, res) => {
        res.json({success: true});
    });
    
    return router;
})();
//index.ts (master file for express.Router)

import * as express from "express";

//import sub-routers
import * as adminRouter from "./admin/admin";
import * as productRouter from "./products/products";

export = (() => {

  let router = express.Router();

  // mount express paths, any addition middleware can be added as well.
  // ex. router.use('/pathway', middleware_function, sub-router);

  router.use('/products', productRouter);
  router.use('/admin', adminRouter);

  //return for revealing module pattern
  return router;
})(); //<--- this is where I don't understand something....

lastly we would set-up our server.js

//the usual node setup
//import * as *** http, body-parser, morgan, mongoose, express <-- psudocode

import * as masterRouter from './routes/index'

var app = express();
//set-up all app.use()

app.use('/api', masterRouter);

http.createServer(app).listen(8080, () => {
      console.log('listening on port 8080')
    };

my main question really is, is index.ts (masterRouter file) and it's nested routes that are IIFe's

export = (function(){})();

should that be the correct/best way to write typescript modules for routers?

or would it be better to use another pattern, perhaps one the utilizes the pattern

export function fnName() {} -- export class cName {} -- export default.

the reason for the IIFe is that when i import them into another file i won't need to initialize the module and there will only ever be 1 instance of each type of router.


Solution

  • In NodeJS each file is a module. Declaring variables does not pollute the global namespace. So you don't need to use the good old IIFE trick to properly scope variables (and prevent global pollution / collision).

    You would write:

      import * as express from "express";
    
      // import sub-routers
      import * as adminRouter from "./admin/admin";
      import * as productRouter from "./products/products";
    
      let router = express.Router();
    
      // mount express paths, any addition middleware can be added as well.
      // ex. router.use('/pathway', middleware_function, sub-router);
    
      router.use('/products', productRouter);
      router.use('/admin', adminRouter);
    
      // Export the router
      export = router;
    

    More on modules: https://basarat.gitbooks.io/typescript/content/docs/project/modules.html