Home » Nodejs » Nodejs, express routes as es6 classes

Nodejs, express routes as es6 classes

Posted by: admin November 29, 2017 Leave a comment

Questions:

I want to clean up my project a bit and now i try to use es6 classes for my routes. My problem is that this is always undefined.

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

class Routes {
    constructor(){
        this.foo = 10
    }

    Root(req, res, next){
        res.json({foo: this.foo}); // TypeError: Cannot read property 'foo' of undefined
    }
}

var routes = new Routes();
app.get('/', routes.Root);
app.listen(8080);
Answers:

try to use the code to pin this:

app.get('/', routes.Root.bind(routes));

You can get out of the boilerplate using underscore bindAll function. For example:

var _ = require('underscore');

// ..

var routes = new Routes();
_.bindAll(routes)
app.get('/', routes.Root);

I also found that es7 allows you to write the code in a more elegant way:

class Routes {
    constructor(){
        this.foo = 10
    }

    Root = (req, res, next) => {
        res.json({foo: this.foo});
    }
}

var routes = new Routes();
app.get('/', routes.Root);

Questions:
Answers:

This is happening because you’ve passed a method as a standalone function to express. Express doesn’t know anything about the class that it comes from, therefore it doesn’t know which value to use as this when your method is called.

You can force the value of this with bind.

app.get('/', routes.Root.bind(routes));

Or you can use an alternative construct for managing routes. You can still make use of a lot of the syntactic benefits for object oriented programming without classes.

function Routes() {
  const foo = 10;

  return {
    Root(req, res, next) {
      res.json({ foo });
    }
  };
}

const routes = Routes();
app.get('/', routes.Root);
app.listen(8080);
  • You won’t have to worry about the value of this
  • It doesn’t matter whether the function is called with new or not
  • You can avoid the complexity of calling bind on each route

There’s a good list of resources here, on why ES6 classes are not as good as they might seem.

Questions:
Answers:

The above answers seem a bit over complicated. Checkout what I’ve done here:

class Routes {
  constructor(req, res, next) {
    this.req = req;
    this.res = res;
    this.next = next;
    this.foo = "BAR"
    // Add more data to this. here if you like
  }

  findAll (){
    const {data, res,} = this; // Or just reference the objects directly with 'this'
    // Call functions, do whaterver here...
    // Once you have the right data you can use the res obejct to pass it back down

    res.json ({foo: this.foo}); // Grabs the foo value from the constructor

  }
}

Now when it comes to using this class you can do something along the lines of this:

var express = require('express');
var router = express.Router();
var {Routes} = require('./Routes');

router.get('/foo', (req, res, next) => {
  new Routes(req, res, next).findAll();
});

I would seperate the two files, so that you just require the Routes class into your Router file.

Hope this helped!

Questions:
Answers:

Or if you don’t like binding the context per routes, you can optionally bind it to methods in your class’ constructor itself.

E.g:

constructor() {
   this.foo = 10;
   this.Root = this.Root.bind(this);
}