How to separate routes on Node.js and Express 4?
Asked Answered
E

9

85

I want to separate Routes from my server.js file.

I am following this tutorial on Scotch.io http://scotch.io/tutorials/javascript/build-a-restful-api-using-node-and-express-4

It is working if all lines are on server.js file. But I am failing to separate. How can I make this work?

server.js

// set up ======================================================================
var express = require('express');
var app = express();
var bodyParser = require('body-parser');

// configuration ===============================================================
app.use(bodyParser());

var port = process.env.PORT || 8000;

var mongoose = require('mongoose');
var database = require('./config/database');
mongoose.connect(database.url);
var Video = require('./app/models/video');

// routes =======================================================================
app.use('/api', require('./app/routes/routes').router);

// listen (start app with node server.js) ======================================
app.listen(port);
console.log("ready captain, on deck" + port);

module.exports = app;

And the app/routes/routes.js

var express = require('express');
var router = express.Router();

router.use(function(req, res, next) {
  console.log('Something is happening.');
  next();
});

router.get('/', function(req, res) {
  res.json({ message: 'hooray! welcome to our rest video api!' });  
});


router.route('/videos')

  .post(function(req, res) {

    var video = new Video();
    video.title = req.body.title;

    video.save(function(err) {
  if (err)
    res.send(err);

  res.json({ message: 'Video criado!' });
});


  })

  .get(function(req, res) {
    Video.find(function(err, videos) {
      if (err)
        res.send(err);

      res.json(videos);
    });
  });

module.exports.router = router;
Electrosurgery answered 28/5, 2014 at 23:16 Comment(9)
whats the node error? i think module.exports = { router: router } in routes.js should do itThatch
Hi @bbuecherl, I am getting a ReferenceError: Video is not definedElectrosurgery
It looks like you have lowercase 'v' for videos and trying to reference uppercase 'V' for videos.Mildredmildrid
Looks like he is not able to find Video, you need to move your line var Video = require("./app/models/video"); from server.js to routes.js.Thatch
@Thatch I tried but it can't find the module... Ben, the code is working when all on server.js...Electrosurgery
When including video.js in route.js, use proper path something like "..\models\video"Roar
@KiranPagar, thank you it worked... "../models/video"Electrosurgery
check this sample wiki.workassis.com/nodejs-express-separate-routes for making a separate route fileBarbule
Does this answer your question? How to include route handlers in multiple files in Express?Hubbs
R
70

As far as separating routes from main file is concerned..

Server.js

//include the routes file
var routes = require('./routes/route');
var users = require('./routes/users');
var someapi = require('./routes/1/someapi');

////////
app.use('/', routes);
app.use('/users', users);
app.use('/1/someapi', someapi);

routes/route.js

//last line - try this
module.exports = router;

Also for new project you can try on command line

express project_name

You will need express-generator for that

Roar answered 28/5, 2014 at 23:40 Comment(3)
This doesn't really separate the routes, it separates the controller. @Bikesh has the more correct solution.Namecalling
I am trying to separate API from main app file then its showing error apiRoutes.post('/register', function(req, res, next) { ^ TypeError: Cannot read property 'post' of undefined at Object.<anonymous> (F:\saurabh_sharma\nodejs\salecrm\app\routes.js:4:10) at Module._compile (module.js:413:34) at Object.Module._extensions..js (module.js:422:10) ...Trusting
ahh i see, i think i can use fs for best solutionFairspoken
B
105

Server.js

var express = require('express');
var app = express();

app.use(express.static('public'));

//Routes
app.use(require('./routes'));  //http://127.0.0.1:8000/    http://127.0.0.1:8000/about

//app.use("/user",require('./routes'));  //http://127.0.0.1:8000/user  http://127.0.0.1:8000/user/about


var server = app.listen(8000, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("Example app listening at http://%s:%s", host, port)

})

routes.js

var express = require('express');
var router = express.Router();

//Middle ware that is specific to this router
router.use(function timeLog(req, res, next) {
  console.log('Time: ', Date.now());
  next();
});


// Define the home page route
router.get('/', function(req, res) {
  res.send('home page');
});

// Define the about route
router.get('/about', function(req, res) {
  res.send('About us');
});


module.exports = router;

*In routs.js you should define Middle ware

ref http://wiki.workassis.com/nodejs-express-separate-routes/

Barbule answered 2/8, 2016 at 10:58 Comment(4)
how can this answer scale when i have more routes? @BikeshRwanda
When using this approach, I noticed my req.body was returning undefined, upon putting it in the index.js again, the body showed up. Any ideas?Luca
@Rwanda just create more files with a different route (routes2.js, etc).Voluptuous
@Voluptuous I wouldn't recommend doing that at all.Rwanda
R
70

As far as separating routes from main file is concerned..

Server.js

//include the routes file
var routes = require('./routes/route');
var users = require('./routes/users');
var someapi = require('./routes/1/someapi');

////////
app.use('/', routes);
app.use('/users', users);
app.use('/1/someapi', someapi);

routes/route.js

//last line - try this
module.exports = router;

Also for new project you can try on command line

express project_name

You will need express-generator for that

Roar answered 28/5, 2014 at 23:40 Comment(3)
This doesn't really separate the routes, it separates the controller. @Bikesh has the more correct solution.Namecalling
I am trying to separate API from main app file then its showing error apiRoutes.post('/register', function(req, res, next) { ^ TypeError: Cannot read property 'post' of undefined at Object.<anonymous> (F:\saurabh_sharma\nodejs\salecrm\app\routes.js:4:10) at Module._compile (module.js:413:34) at Object.Module._extensions..js (module.js:422:10) ...Trusting
ahh i see, i think i can use fs for best solutionFairspoken
S
24

Another way to separate routes into their own files with Express 4.0:

server.js

var routes = require('./routes/routes');
app.use('/', routes);

routes.js

module.exports = (function() {
    'use strict';
    var router = require('express').Router();

    router.get('/', function(req, res) {
        res.json({'foo':'bar'});
    });

    return router;
})();
Starlastarlene answered 9/11, 2014 at 15:6 Comment(5)
Why 'use strict'; inside the function?Ljoka
@KarlMorrison I guess it's just to satisfy linters.Sibelius
What is the benefit here in wrapping the whole route definition in a (function() { ... })() construct ?Batchelder
@SylvainLeroux - Node has file-level variable scope, so there is no benefit to the IIFE in this context that I can see. It should be taken out.Namecalling
I was having issues with app.use('/', routes) so I had to just use app.use(routes). All of my routes were just hitting router.get('/').Flyblown
C
14

One way to separate routes into their own file.

SERVER.JS

var routes = require('./app/routes/routes');  //module you want to include
var app=express();
routes(app);   //routes shall use Express

ROUTES.JS

module.exports=function(app) {
 //place your routes in here..
 app.post('/api/..., function(req, res) {.....}   //example
}
Classmate answered 29/5, 2014 at 15:21 Comment(1)
I'm not a big fan of passing app around all over the place. It' not a tidy solution.Namecalling
C
6

If you're using express-4.x with TypeScript and ES6, this would be a 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 clear and reliable rather using var and module.exports.

Cabbage answered 29/3, 2019 at 21:6 Comment(0)
R
3

We Ought To Only Need 2 Lines of Code

TL;DR

$ npm install express-routemagic --save
const magic = require('express-routemagic')
magic.use(app, __dirname, '[your route directory]')

That's it!

More info:

How you would do this? Let's start with file structuring:

project_folder
|--- routes
|     |--- api
|           |--- videos
|           |     |--- index.js
|           |
|           |--- index.js
|     
|--- server.js

Note that under routes there is a structure. Route Magic is folder aware, and will imply this to be the api uri structure for you automatically.

In server.js

Just 2 lines of code:

const magic = require('express-routemagic')
magic.use(app, __dirname, 'routes')

In routes/api/index.js

const router = require('express').Router()

router.get('/', (req, res) => { 
    res.json({ message: 'hooray! welcome to our rest video api!' })
})

In routes/api/videos/index.js

Route Magic is aware of your folder structure and sets up the same structuring for your api, so this url will be api/videos

const router = require('express').Router()

router.post('/', (req, res) => { /* post the video */ })
router.get('/', (req, res) => { /* get the video */ })

Disclaimer: I wrote the package. But really it's long-overdue, it reached my limit to wait for someone to write it.

Rwanda answered 16/5, 2020 at 8:26 Comment(0)
B
2

An issue I was running into was attempting to log the path with the methods when using router.use ended up using this method to resolve it. Allows you to keep path to a lower router level at the higher level.

routes.js

var express = require('express');
var router = express.Router();

var posts = require('./posts');

router.use(posts('/posts'));  

module.exports = router;

posts.js

var express = require('express');
var router = express.Router();

let routeBuilder = path => {

  router.get(`${path}`, (req, res) => {
    res.send(`${path} is the path to posts`);
  });

  return router

}

module.exports = routeBuilder;

If you log the router stack you can actually see the paths and methods

Boult answered 22/9, 2017 at 12:14 Comment(0)
D
1

I simply delcared the files and used require in the server.js file

 app.use(express.json());
 require('./app/routes/devotion.route')(app);
 require('./app/routes/user.route')(app);
Domenicadomenico answered 28/9, 2022 at 12:22 Comment(0)
L
0

In my case, I like to have as much Typescript as possible. Here is how I organized my routes with classes:

export default class AuthService {
    constructor() {
    }

    public login(): RequestHandler {
       return this.loginUserFunc;
    }

    private loginUserFunc(req: Request, res: Response): void {
        User.findOne({ email: req.body.email }, (err: any, user: IUser) => {
            if (err)
                throw err;
            if(!user)
                return res.status(403).send(AuthService.noSuccessObject());
            else
                return AuthService.comparePassword(user, req, res);
        })
    }
}

From your server.js or where you have your server code, you can call the AuthService in the following way:

import * as express from "express";
import AuthService from "./backend/services/AuthService";

export default class ServerApp {
    private authService: AuthService;

    this.authService = new AuthService();

    this.myExpressServer.post("/api/login", this.authService.login(), (req: express.Request, res: express.Response) => {
    });
}
Lymphoblast answered 7/3, 2017 at 8:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.