Search code examples
node.jsexpresspg-promise

how to chain statements together using promises


I'm new to node, and learning all about promises, and pg-promise specifically. This is what I want to do using Express and pg-promise:

  1. check email,
  2. if not found check username,
  3. if not found create a new user.
  4. return user id

I've got my repo set up (db.users) which does the sql which is working great.

In my authorization handler I'm not sure how to make the repo calls follow one another. The syntax seems clunky to me. Here's what I have so far:

exports.signup = function( req, res, next ) {

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

 // See if a user with the given email exists
     db.users.byEmail({email: email})
      .then(user => {
        if (user) {
         return res.status(422).send({ error: 'Email is in use'});
       } else { 
         return null;   <-- must I return something here?
       }
      })
   .then(() => {
     db.users.getUsername({username: username})
     .then(user => {
        if (user) {
         return res.status(422).send({ error: 'Email is in use'});
       } else { 
         return null;   <-- must I return something here?
       }

       ...etc

   })

Maybe pg-promises don't chain together like this? Should they be nested within one another or maybe be completely separate blocks? Also, not quite sure where the catch goes. I've tried every way I can think of, following various tutorials, but I get errors like 'can't set headers that already set' and 'promises aren't being returned'. If any kind person can guide me here, I'd really appreciate it.


Solution

  • With guidance from vitaly-t I altered his answer to include separate error messages depending on which thing failed. I also moved up the next "then" into the transaction block to use the "t" of the transaction for the next step which creates user. Much thanks for vitaly-t!

    db.task(t => {
        return t.users.byEmail({email})
          .then(user => {
              if (user) {
                throw new Error('Email is in use');
              } else {
                return t.users.byUsername({username});
            }
          })
          .then((user) => {
              if (user) {
                  throw new Error('Username is taken');
              } else {
                  return t.users.addNew({username, email, password});
              }
          })
    })
    .then(user => {
        res.json({token: tokenForUser(user), username: user.username, aCheck: user.is_admin});
    })
    .catch(error => {
        res.status(422).json({ 'error': error.message});
    });