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
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",
}),
});
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
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:
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;
})
},
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);
}
});