Jamgreen
Jamgreen

Reputation: 11059

Throw errors outside of promise

I have a function to log in a user which should return JSON.

const username = req.body.username;
const password = req.body.password;

if (!username) {
  throw new Error('Missing username');
}

if (!password) {
  throw new Error('Missing password');
}

User.findOne({ username, password }).then(user => {
  res.json({ user });
}).catch(err => {
  res.json({ err });
});

but then the errors for missing username or missing password are not returned in JSON.

I could change it to

const username = req.body.username;
const password = req.body.password;

if (!username) {
  res.json({ err: 'Missing username' });
}

if (!password) {
  res.json({ err: 'Missing password' });
}

User.findOne({ username, password }).then(user => {
  res.json({ user });
}).catch(err => {
  res.json({ err });
});

but it seems a little redundant.

Is the correct way to do it to encapsulate it in a promise?

Upvotes: 1

Views: 2049

Answers (4)

marvel308
marvel308

Reputation: 10458

you can wrap your functions in a promise and handle it efficiently

function getRes(){  
    return new Promise(function(resolve, reject){
        const username = req.body.username;
        const password = req.body.password;

        if (!username) {
          reject(new Error('Missing username'));
        }

        if (!password) {
          reject(new Error('Missing password'));
        }

        resolve(User.findOne({ username, password }));
    });
}


getRes().then(function(result){
    res.json(result);
}).catch(function(err){
    res.json(err);
})

Upvotes: 0

CFrei
CFrei

Reputation: 3627

I'm taking the example from @alexmac and use es6 async feature:

function validateParams() {
  const username = req.body.username;
  const password = req.body.password;

  if (!username) {
    throw new Error('Missing username');
  }
  if (!password) {
    throw new Error('Missing password');
  }
  return { username, password };
}

async function resolver() {
    try {
        await resolve()
        let filter = validateParams()
        let user = await User.findOne(filter)
        await res.json(user)
    } catch (e) {
        await res.json(e)
    }
 }

and that would look more elegant by using an if instead of a throw:

async function(req, res) {
    const password = req.body.password
    const username = req.body.username
    let c = !password ? 'missing password' : 
                !username ? 'missing username' : null
    if (!c) {
       c = await User.findOne({ username, password })
    }
    await res.json(c)
}

Upvotes: 0

alexmac
alexmac

Reputation: 19617

In your first solution, the thrown errors won't be handled, because you throw them outside of promise chain and without try/catch block. In your second solution you can get cannot send headers after they sent error, because the response can be sent twice (username is missing and password is missing).

So the one of the possible solutions here, is to create a promise chain (using Promise.resolve()) and validate parameters here:

function validateParams() {
  const username = req.body.username;
  const password = req.body.password;

  if (!username) {
    throw new Error('Missing username');
  }
  if (!password) {
    throw new Error('Missing password');
  }
  return { username, password };
}

Promise
  .resolve()
  .then(validateParams)
  .then(filter => User.findOne(filter))
  .then(user => res.json(user))
  .catch(err => res.json(err));

Upvotes: 2

jlaitio
jlaitio

Reputation: 1948

The obvious way would indeed be to encapsulate them in a promise to start your promise chain (with the User.findOne being inside the first then-block) - that way your current error handler catches them just fine.

Upvotes: 0

Related Questions