0

I'm working on a REST API in node.js and I'm encountering a problem when trying to pass a value from one module to another, I'm rather new to node.js there is something I'm definitely missing something here...

I have a controller and a "service" module for authentication which uses JWT. What I'm trying to do is pass a user object to the auth service in order to obtain the JWT and pass it back to the controller in order to build the response.

In the service I get the JWT with no problems but I cannot pass it back... the return param; does not work in this case.

Here is the function from my controller

exports.login = (req, res) => {
    const email = req.body.email;
    const password = req.body.password;

    Users.findOne({ 'email': email, 'password': password }, (err, user) => {
        if (err) {
            res.json({ err });
        } else {
            if (typeof user !== null) {                
                var token = authService.generateToken(user);
                res.json({
                    token
                });

            } else {
                res.json({
                    status: 'error',
                    message: 'User not found!'
                });
            }

        }
    })
};

And here is the function from my authService (which is inclunded in the controller)

exports.generateToken = function(user) {
    jwt.sign({ user }, params.secret, { expiresIn: params.expires }, (err, token) => {
        if (err)
            return err;
        console.log(token);
        return token;
    });
}

Now that console.log(token) from the authService returns the valid JWT in the console, but in the controller I get nothing back.

Can someone please help me with this?

Thanks!

3
  • Possible duplicate of How do I return the response from an asynchronous call? Commented Feb 27, 2018 at 15:01
  • @PatrickRoberts I've tried with the callback param in the generateToken function instead of return but I could not make it work even like that... could you please take look over it maybe it's a 1m solution to this that I've failed to implement Commented Feb 27, 2018 at 15:14
  • you have to use callback. Commented Feb 27, 2018 at 15:40

1 Answer 1

1

You can't return something from an asynchronous callback. You have to provide a callback function to pass the value to:

exports.login = (req, res) => {
  const email = req.body.email;
  const password = req.body.password;

  Users.findOne({ email, password }, (err, user) => {
    if (err) {
      res.json({ err });
    } else {
      if (typeof user !== null) {                
        authService.generateToken(user, req, (err, token) => {
          res.json({
            token
          });
        });
      } else {
        res.json({
          status: 'error',
          message: 'User not found!'
        });
      }
    }
  });
};

exports.generateToken = function(user, req, callback) {
  jwt.sign({ user }, req.params.secret, { expiresIn: req.params.expires }, callback);
}

Alternatively, you can convert your callbacks to promises to somewhat flatten your asynchronous flow:

exports.login = (req, res) => {
  const email = req.body.email;
  const password = req.body.password;

  Users.findOne({ email, password }).then(user => {
    if (user === null) throw new Error('User not found');
    return authService.generateToken(user, req);
  }).then(token => {
    res.json({ token });
  }).catch(error => {
    res.json({ status: 'error', message: error.message });
  });
};

exports.generateToken = (user, req) => new Promise((resolve, reject) => {
  jwt.sign({ user }, req.params.secret, { expiresIn: req.params.expires }, (error, token) => {
    if (error) reject(error);
    else resolve(token);
  });
});

And finally, leaving exports.generateToken() as written above, you can convert your promise-based exports.login() to an async function:

exports.login = async (req, res) => {
  const email = req.body.email;
  const password = req.body.password;

  try {
    const user = await Users.findOne({ email, password });

    if (user === null) throw new Error('User not found');

    const token = await authService.generateToken(user, req);

    res.json({ token });
  } catch (error) {
    res.json({ status: 'error', message: error.message });
  }
};
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.