Browsers needs a HTTP response, but server is not allowing multiple responses - javascript

This is my handler that sends out a PUT request to my server:
export function insertRandomQuestionsHandler(roomId, questions) {
return (dispatch) => {
dispatch(questionOverviewHandler(questions));
let result = questions.reduce((r, e) => (r.push(...e), r), []);
const url = . `http://localhost:3000/quizzer/room/${roomId}/selectedQuestions`;
const response = fetch(url, {
method: "PUT",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
questions: result,
})
});
if (response.error) {
throw new Error(`HTTP PUT request went wrong: got .
"${response.statusText}" for "${url}"`)
}
dispatch(insertRandomQuestions(result))
}
}
On the server it goes through this request:
quizzer.put('/room/:roomId/selectedQuestions', async function (req, res) {
for (let i = 0; i < req.body.questions.length; i++) {
await Room.findOneAndUpdate({roomId: req.params.roomId}, {
"$push": {
"questions": [{
"_id": req.body.questions[i]._id,
"question": req.body.questions[i].question,
"answer": req.body.questions[i].answer,
"category": req.body.questions[i].category,
"isShown": false,
}]
}
},(err, data) => {
if (err) {
return res.status(500).send(err);
}
return res.status(200).json(data);
});
}
});
For some reason the browser needs a response else the request will be stuck at being pending and eventually return ERR_EMPTY_RESPONSE:
But when I return a response (data) as shown above (the http request is 200)
Then my server crashes:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent
So... I need that response to be sent, but it can't be sent twice..
Any ideas?

Related

How to get a response from nodemailer using netlify functions?

I am using netlify functions to send an email from the frontend and it works fine... as in it does send the email.
However on the clientside (browser) I can't get any response. I need a basic response that would allow me to do a if (status==="success") displayMessage() but I can't seem to get any response on the browser.
I get this message Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data However on sending the request via POSTMAN I get a response 'Email Sent Succesfully' which is the body part of the callback response.
Here's the function that I am using at .netlify/functions/sendMail
const nodemailer = require("nodemailer");
exports.handler = function (event, context, callback) {
const mailConfig = {
host: "smtp.mailgun.org",
port: 465,
secure: true,
auth: {
user: process.env.MAILGUN_USER,
pass: process.env.MAILGUN_PASSWORD,
},
};
const transporter = nodemailer.createTransport(mailConfig);
transporter.verify((error, success) => {
if (error) {
console.log(error);
} else {
console.log("Ready to send emails");
}
});
const messageData = JSON.parse(event.body);
const { email, name, mobile, message, subject, recipient } = messageData;
console.log(messageData);
const mailOptions = {
from: email,
to: recipient,
subject: subject,
text: message,
};
transporter.sendMail(mailOptions, (error, success) => {
if (error) {
console.log(error);
callback(error);
} else {
console.log("email sent");
callback(null, {
statusCode: 200,
body: "Email sent successfully",
});
}
});
};
and on the client side I have this
const form = document.querySelector("#message");
const submitMessage = (event) => {
event.preventDefault();
const formData = new FormData(form);
formData.append("recipient", "testing#gmail.com");
formData.append("subject", "Submission from website");
const messageData = Object.fromEntries(formData);
console.log(messageData);
const url = ".netlify/functions/sendMail";
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(messageData),
};
fetch(url, options)
.then((response) => response.json())
.then((data) => console.log(data));
};
form.addEventListener("submit", submitMessage);
in the fetch request, I expected data to give me a response so I could trigger some action to display a success message..
Can someone advise me what I am doing wrong here?
I realised what I was doing wrong and here's the solution in case someone else faces the same issues.
In the callback from the netlify function I was sending the body as text
callback(null, {
statusCode: 200,
body: "Email sent successfully",
});
but in the clientside fetch request I was treating it as json
fetch(url, options)
.then((response) => response.json())
.then((data) => console.log(data));
So basically I could either use a response.text() instead of response.json() for the fetch request or use JSON.stringify and return a JSON object from the callback. I preferred the JSON.stringify option as below for the callback
callback(null, {
statusCode: 200,
body: JSON.stringify({
status: "success",
message: "Email sent successfully",
}),
});

Cookie error while trying to authenticate for data scraping

I'm trying to scrape some data from truepush website, but first it needs to be authenticated. So here is what I'm doing:
const loginUrl = 'https://app.truepush.com/api/v1/login'
let loginResult = await axios.get(loginUrl)
.then(({ headers }, err) => {
if (err) console.error(err);
return headers['set-cookie'][0];
})
.then((cookie, err) => {
if (err) console.error(err);
const splitByXsrfCookieName = cookie.split("XSRF-TOKEN=")[1]
return splitByXsrfCookieName.split(';')[0];
}).then(xsrfToken => {
return axios.post(loginUrl, {
headers: {
"Content-Type": "application/json",
"X-XSRF-TOKEN": xsrfToken
}
})
}).then(res => console.log(res))
It throws xrsfToken on second then response and when I try to login in third response with that xsrf token, it shows me this error:
{
"status_code": "XSRF-ERROR",
"status": "ERROR",
"message": "Cross domain requests are not accepting to this endpoint. If you cleared the cookies, please refresh your browser."
}
I'm not sure what wrong I'm doing :(
The main issue is that the call also requires the original cookie to be sent. You need to keep the original cookie your get from set-cookie header and pass it in cookie header in the second call like cookie: originalCookie. Also in your code, there is no body sent in the POST call.
The following code reproduces the login :
const axios = require("axios");
const originalUrl = 'https://app.truepush.com';
const loginUrl = 'https://app.truepush.com/api/v1/login';
const email = "your-email#xxxxxx";
const password = "your-password";
(async () => {
await axios.get(originalUrl)
.then(({ headers }, err) => {
if (err) console.error(err);
const cookie = headers['set-cookie'][0];
return {
cookie: cookie,
xsrfToken: cookie.split("XSRF-TOKEN=")[1].split(";")[0]
};
})
.then((data, err) => {
if (err) console.error(err);
return axios.post(loginUrl, {
"email": email,
"password": password,
"keepMeLoggedIn": "yes"
}, {
headers: {
"X-XSRF-TOKEN": data.xsrfToken,
"cookie": data.cookie
}
})
})
.then(res => console.log(res.data))
})();
Output:
{
status_code: 'SUCCESS',
status: 'SUCCESS',
message: 'Login Successful',
data: {
id: 'xxxxxxxxxxxxxxxxxxx',
name: 'xxxxx',
email: 'xxxxxxx#xxxxxx'
}
}
Note that both cookie and xsrfToken are consumed by the second promise

How can I fetch the error message from 422 Unprocessable Entity response?

I need some help about to get the error message from 422 Unprocessable Entity response.
I have this function as you can see here:
const upDateMyProfile = async (path, data) => {
state.loading = true
try {
const account = {
account_gender: data.value.account.gender,
account_firstname: data.value.account.firstname,
account_lastname: data.value.account.lastname,
partner_gender: data.value.partner.gender,
partner_firstname: data.value.partner.firstname,
partner_lastname: data.value.partner.lastname
}
const req = await fetch(`${url}/${path}`, {
method: 'PUT',
body: JSON.stringify(account),
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${AUTH_TOKEN.accesstoken}`
}
})
state.toast = true
state.statusCode = req.status
if (req.status !== 204) {
console.log()
}
return req
} catch (error) {
state.error = error
state.toast = true
} finally {
state.loading = false
setTimeout(() => {
state.toast = false
}, TIMEOUT)
}
}
Is a function to update a user profile details and the problem I have is I don't know how to get the error message from the server when a user sends an invalidate data value or leave a mandatory field empty.
The server respond with a 422 error:

HTTP request not working when done in code

I am making a request and everything is correct but the issue I have is I keep getting a 404 error. but if I copy the parameters and body with that same url to postman it returns a success. I do not know what I am doing wrong.
const promisify = require('util').promisify;
const { post, get, del } = require('request');
const postAsync = promisify(post);
post: async (url, payload) => {
console.log('USER ID PAYLOAD',payload)
return postAsync(url, {
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
json: true,
body: payload
})
.then(response => {
console.log('USER ID StAtUS CODE', response.url, response.body)
if (response.statusCode >= 400) throw new Error(response.body.message || "An error occurred");
if (response.body && response.body.status === 'error' || response.body.status === 'fail') throw new Error(response.body.message || "An error occurred");
return response.body;
}, error => {
throw error;
})
},

Using the Node Request module with AWS Lambda and API Gateway

This lambda function works:
exports.handler = function(event, context, callback) {
const done = (err, res, func) => callback(null, {
statusCode: '200',
body: res,
headers: { 'Content-Type': 'application/json' },
})
done(null, 'works'))
}
I can hit the API Gateway end point and receive the response message, 'works'.
However, when I add a request call (POSTing a message to Slack) that looks like this:
const request = require('request')
const moment = require('moment-timezone')
exports.handler = function(event, context, callback) {
// the json object is built following these docs:
// https://api.slack.com/docs/message-attachments
const SLACK_WEB_HOOK_URL = process.env.SLACK_WEB_HOOK_URL
const uri = SLACK_WEB_HOOK_URL
const method = 'POST'
const options = {
json,
uri,
method,
}
const slack = (opts) => {
request.post(opts, (err, response, body) => {
if (response.statusCode < 300) {
return 'Success!'
} else {
return 'Err!'
}
})
}
const done = (err, res, func) => callback(null, {
statusCode: '200',
body: res,
headers: { 'Content-Type': 'application/json' },
})
done(null, slack(options))
}
The server hangs when I hit the API end point ...
And I get a Task timed out after 10.00 seconds error:
{
"errorMessage": "2017-06-23T16:41:21.483Z c385e32e-5832-11e7-8c4f-673b524cf783 Task timed out after 10.00 seconds"
}
But my Slack POST request gets sent and I see the message in the channel.
How do I send the POST request and then wait for it to return, and then exit the lambda function with a custom response message?
Thanks for the help!
Put the callback into the callback of the post method
request.post(opts, (err, response, body) => {
if (response.statusCode < 300) {
return callback(null, {
statusCode: '200',
body: res,
headers: { 'Content-Type': 'application/json' },
});
} else {
return callback(err);
}
});

Categories