Skip to content
Advertisement

Why can’t I redirect to my failure page using node.js?

I am working on my newsletter project using Mailchimp API, it works but I can’t redirect to a failure page if the status code is not 200, the browser says localhost refused to connect meanwhile success page redirection works great. here’s my code:

app.post("/", async(req, res, next)=>{
  const {fName, lName, email} = req.body.user;
  const response = await mailchimp.lists.addListMember("List_ID", {
    email_address: email,
    status: "subscribed",
    merge_fields:{
      FNAME: fName,
      LNAME: lName,
    },
  });
  if(res.statusCode === 200){
    res.sendFile(__dirname + "/success.html");
  }
  else{
    res.sendFile(__dirname + "/failure.html");
  }

});

Advertisement

Answer

First of all using async with express is tricky, if anything in your async function throws express won’t get notified about that which would result in an error like:

localhost refused to connect

A quick and dirty solution would be to warp your whole body of the async function into a try .. catch block. But that’s tedious and you might still miss some side conditions.

So instead you would want to create a wrapper for that which could look that way: (There are probably better implementations for an express async wrapper)

function asyncExpressWrapper(fn) {
   // return the wrapping middelware be used.
   return async (req, res, next) => {
      try {
         // call the actual middelware you passed
         await fn(req, res, next);
      } catch (err) {
         // will catch any error thrown in fn
         next(err)
      }
   }
}

And use it that way:

app.post("/", asyncExpressWrapper(async(req, res, next) => {
  const {
    fName,
    lName,
    email
  } = req.body.user;

  const response = await mailchimp.lists.addListMember("List_ID", {
    email_address: email,
    status: "subscribed",
    merge_fields: {
      FNAME: fName,
      LNAME: lName,
    },
  });

  if (response.statusCode === 200) {
    res.sendFile(__dirname + "/success.html");
  } else {
    res.sendFile(__dirname + "/failure.html");
  }
}));

Now that will solve the localhost refused to connect problem, and express will tell you which error you didn’t handle.

Besides that your res.statusCode === 200 will check the express response statusCode which at that point is always true, if response has a statusCode it has to be response.statusCode === 200.

Now your __dirname + "/failure.html" likely still is not shown, as the Promise returned by mailchimp.lists.addListMember likely rejects in the error case. So you needd also a try ... catch in your middleware:

app.post("/", asyncExpressWrapper(async(req, res, next) => {
  const {
    fName,
    lName,
    email
  } = req.body.user;
  
  try {
    const response = await mailchimp.lists.addListMember("List_ID", {
      email_address: email,
      status: "subscribed",
      merge_fields: {
        FNAME: fName,
        LNAME: lName,
      },
    });

    // you probably don't need that if-else at all and only emit 
    // success here, but I don't know mailchimp.lists.addListMember 
    // so that's up to you to figure out. 
    if (response.statusCode === 200) {
      res.sendFile(__dirname + "/success.html");
    } else {
      res.sendFile(__dirname + "/failure.html");
    }
  } catch(err) {
    res.sendFile(__dirname + "/failure.html");
  }
}));

The Express documentation has a section about Promises suggesting this as a wrapper:

const wrap = fn => (...args) => fn(...args).catch(args[2])

The one I suggested also works if you pass a none async function to it from which you accidentally don’t return a Promise.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement