Search code examples
javascriptnode.jsexpressmiddleware

Calling object functions in middleware


I have this code in my middleware:

const UserMiddleware = {

  isNumber(n) { return !Number.isNaN(parseFloat(n)) && !Number.isNaN(n - 0); },

  // eslint-disable-next-line consistent-return
  validateSignUp(req, res, next) {
    const allSignUpErrors = [];
    console.log(this.isNumber(5));
    if (this.isNumber(req.body.first_name)) {
      allSignUpErrors.push('First name must be a text value');
    }
    if (allSignUpErrors.length !== 0) {
      return res.status(400).json({
        status: 400,
        error: allSignUpErrors,
      });
    }
    next();
  },

I normally use 'this.' to call functions and variables in objects without problems. I suspect that the 'next()' function in the middleware is what is causing me to get the error below at the point of using 'this.' to call a function.

TypeError: Cannot read property 'isNumber' of undefined

I have tried using 'bind' to call the function but the 'undefined' error still occurs.

Is the 'next()' function the one breaking the normal functionality? Is there a way to correctly use 'this.' to call functions in middleware?


Solution

  • Change:

    this.isNumber(...)
    

    to:

    UserMiddleware.isNumber(...)
    

    The value of this inside a middleware function will not be your UserMiddleware object unless you specifically used .bind() or some similar technology when passing it as middleware.


    For help with further options, show us the code where you're using validateSignUp().

    For example, if you were doing:

    app.use(UserMiddleware.validateSignUp);
    

    Then, you could set the desired value for this by using .bind() like this:

    app.use(UserMiddleware.validateSignUp.bind(userMiddleware));
    

    Passing UserMiddleware.validateSignUp to a function immediately loses the association with the UserMiddleware object and the this value when that function gets called will be determined by how the caller calls the function and won't be the UserMiddleware object. Using .bind(UserMiddleware) forces the desired this value to be set. .bind() actually creates a wrapper function who's sole job is to reattach the desired this value and that wrapper function is what is passed as the middleware handler. The middleware infrastructure calls the wrapper function with the wrong this value and then the wrapper function calls your validateSignUp function with the desired value of this - probably using .apply().

    For a look at how .bind() works, you can see a polyfill for it here on MDN. For more of a discussion of how the value of this is set, see Six ways of setting this.