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.