I am following a MailChimp API tutorial
When I test the API, I get a 401 response saying my API key is invalid.
Error -
Status: 401
"Your API key may be invalid, or you've attempted to access the wrong datacenter."
I have yet to register a domain yet, this is being testing using a local server. Could this be error be caused by MailChimp's refusing the request for another reason, perhaps CORS?
app.post('/signup', (req, res) => {
// Get form data
const { email } = req.body;
// Make sure field is filled
if(!email) {
res.redirect('/html/fail.html');
return;
}
// Construct req data
const data = {
members: [
{
email_address: email,
status: 'subscribed'
}
]
}
// Convert to JSON
const postData = JSON.stringify(data);
const options = {
url: 'https://us19.api.mailchimp.com/3.0/lists/listID',
method: 'POST',
headers: {
Authorization: 'auth xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us19'
},
body: postData
};
request(options, (err, response, body) => {
if(err) {
console.log(err);
res.redirect('/html/fail.html');
} else {
if(response.statusCode === 200) {
res.redirect('/html/success.html');
} else {
console.log(response.body);
res.redirect('/html/fail.html');
}
}
});
})
I tried running the same code in request in PostMan and I got back a 200 response.
I was initially importing the API key from a config file, that I had not destructured...
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 setup a lambda function to authenticate, validate, and handle sending of a contact form..
I'm new to lambda functions so my code may be flawed, but no matter what I do I can't seem to modify the response that is sent back to my vue.js app.
I keep getting "response undefined" ...
Can some explain what I'm doing wrong, and maybe a better way to change the data returned based on what's going on in my function?
const axios = require('axios');
const FormData = require('form-data');
const AUTH_API_ENDPOINT = 'https://www.mywebsite.com/wp-json/jwt-auth/v1/token/'
const FORM_API_ENDPOINT = 'https://www.mywebsite.com/wp-json/contact-form-7/v1/contact-forms/1217/feedback'
const captchaThreshhold = 0.5
exports.handler = async function(event, context) {
const eventBody = JSON.parse(event.body)
const captchaSecret = process.env.CAPTCHA_SECRET
const captchaToken = eventBody.token
const stringFormData = eventBody.formData
let parsedFormData = JSON.parse(stringFormData)
let formData = new FormData()
var response;
//build a new FormData object
for ( var key in parsedFormData ) {
formData.append(key, parsedFormData[key])
}
// first step is to validate the captcha..
//let response_captcha
try {
response = await axios.post(`https://www.google.com/recaptcha/api/siteverify?secret=${captchaSecret}&response=${captchaToken}`,{})
} catch(err) {
return {
statusCode: 200,
body: JSON.stringify({
status: 'error',
message: 'Opps! The server tried to run an AI algorithm to determine if you are a spam robot, but the server did not respond properly so we are unable to continue contact form security verification... Please try again later or contact via phone instead. We appologize for the inconvenience.',
error: err.message
})
}
}
// if we're over the threshold we continue and get a fresh JWT
if (response.data.score >= captchaThreshhold) {
// let response_jwt
try {
response = await axios.post(AUTH_API_ENDPOINT,{
username: process.env.AUTH_USERNAME,
password: process.env.AUTH_PASSWORD,
}).then(res => {
// JWT token returned something.. lets try to submit our form data with authentication code..
axios.post(FORM_API_ENDPOINT, formData, {
headers: {
'Authorization': `Bearer ${res.data.token}`,
'Content-Type': 'multipart/form-data; charset="utf-8"',
...formData.getHeaders()
}
})
.then( res => {
console.log('>> response came back from the Form endpoint : ',res.data.status, res.data.message)
return {
statusCode: 200,
body: {
status: res.data.status,
message: res.data.message
}
}
})
.catch( err => {
console.log('>> something went wrong while trying to submit formData to form endpoint ',err.response.data);
return {
statusCode: 200,
body: JSON.stringify({
status: 'error',
error: err.message,
message: 'Yikes! The form data was processed and sent to our email server but there was no response back. Our developer will look into this shortly. In the meantime, please try again later or contact via phone. We appologize for the inconvenience.'
})
}
})
}).catch( err => {
console.log('>> something went wrong while trying to fetch JWT from endpoint ',err.response.data);
return {
statusCode: 200,
body: JSON.stringify({
status: 'error',
error: err.message,
message: 'Yikes! The form data was processed and sent to our email server for authentication but got no response back.. This is a server issue so our developer will look into this shortly. In the meantime, please try again later or contact via phone. We appologize for the inconvenience.'
})
}
})
} catch(err) {
return {
statusCode: 200,
body: JSON.stringify({
status: 'error',
error: err.message,
message: 'Yikes! The form data was processed and sent to our email server but the server was unable to authenticate the request. This is a server issue so our developer will look into this shortly. In the meantime, please try again later or contact via phone. We appologize for the inconvenience.'
})
}
}
} else {
// user failed the captcha test.. is probably a robot..
return {
statusCode: 200,
body: JSON.stringify({
status: 'error',
message: "Error! Captcha Failed: our AI algorithms tried to determine if you are a robot or a human, it seems they couldn't decide, therefor for security reasons your form submission was blocked. Perhaps try again later, or contact via phone. We appologize for any inconvenience. :("
})
}
}
//send back the response..
return response
}
Maybe something more like:
exports.handler = function(event, context) {
return new Promise((resolve, reject) => {
axios.post(...args).then(response => {
if(bool){
axios.post(...moreArgs).then(response => {
resolve('ok!')
}).catch(reject)
} else {
reject('not bool!')
}
}).catch(reject)
})
}
I feel like async / await makes this more complicated than without it.
I want to use a Google Cloud Function with a http trigger to write data into a Google Spreadsheet.
The following code is my cloud function:
exports.writeDataMaterialCollection = functions.https.onRequest(
(req, res) => {
if (req.method === "POST") {
console.log(req.body);
res.set("Access-Control-Allow-Origin", "*");
const sheets = google.sheets({ version: "v4" });
var jwt = getJwt();
var apiKey = getApiKey();
var spreadsheetId = "sheetIDxxxxxxxxx";
var range = "A:L";
var row = ["data"];
sheets.spreadsheets.values.append(
{
spreadsheetId: spreadsheetId,
range: range,
auth: jwt,
key: apiKey,
valueInputOption: "RAW",
resource: { values: [row] }
},
(err, result) => {
if (err) {
throw err;
} else {
console.log(result.data.updates.updatedRange);
res.status(200).send(result.data.updates.updatedRange);
}
}
);
}
}
);
When I make a curl POST request, then the data is written to the spreadsheet correctly.
url -d '{"test": "wert"}' -X POST http://localhost:5001/XXXX/writeDataMaterialCollection
Problem
What I don't understand is when I use Axios inside Vue.js, Google Cloud Function returns throw new Error("Function timed out.")
axios(
"http://localhost:5001/XXXXX/writeDataMaterialCollection",
{
method: "POST",
headers: {
"content-type": "application/json",
"Access-Control-Allow-Origin": "*"
},
data: {
daten1: 23
}
}
).then(response => (self.writeDataResult = response));
If your function gets to the point of this line:
throw err;
It will not actually terminate the function and propagate that error to the client. That's because you're throwing an error out of a callback function, not the main function. This also means that function will timeout, because no response is being sent to the client.
What you should do instead is send an error to the client, so the function can correctly terminate, and the client can receive the error. You might want to consider logging the error as well, so you can see in the console what went wrong:
if (err) {
res.send(500);
console.error(err);
}
I have a post request that submits a patient name and the server is supposed to give me back patient_id in response. I get a 200 response back to the client however I don't get the patient_id back which is what I need. When I console log on the server i can see patient.id is generated and there are no errors either. Wonder if there is something I am missing?
Response -
body: (...), bodyUsed: false, headers: Headers {}, ok: true, redirected: false, status: 200, statusText: "OK", type: "basic", url: "http://localhost:4000/patient/add"
//client side post
handleSubmit(e) {
e.preventDefault();
const postUrl = '/patient/add';
fetch(postUrl, {
method: 'POST',
headers: {'Content-Type': 'text/plain'},
body: this.state.patientName
})
.then(response=> {
if (!response.ok) console.log('failed', response);
else console.log(response);
});
}
this.app.post('/patient/add', bodyParser.text(),
this.route_post_patient_add.bind(this));
async route_post_patient_add(req, res) {
/** #type {string} */
const body = req.body;
if (body === undefined) {
logger.warning('Set room patient failed, body missing');
res.sendStatus(400);
return;
}
if (body === "") {
logger.warning(' body is empty');
res.sendStatus(400);
return;
}
try {
const patient_id = await this.save_patient(body);
res.send(patient_id);
console.log(patient_id); //logs the id that is generated
}
catch (err) {
logger.error('Set patient failed, internal error', { err });
res.sendStatus(500);
}
}
The response object in fetch is not the raw body.
You have to call a function and resolve a promise to get the data.
For example:
fetch("foo")
.then(parse_body)
.then(log_data);
function parse_body(response) {
return response.text();
}
function log_data(response_text) {
console.log(response_text);
}
Further reading: MDN: Using Fetch
I get a 403 "You must specify an API key to make request" when trying to get data from a 3rd party API (Klaviyo).
const { id } = req.body
request.get({
url: `https://a.klaviyo.com/api/v1/person/${id}`,
headers: {
api_key: process.env.KLAVIYO_API_KEY
}
}, (error, response, body) => {
const profile = JSON.parse(body)
console.log(profile)
if (response.statusCode === 200) {
res.json({ profile, status: 201 })
} else {
res.json({ error: 'Did not get customer data', status: 500, response: response, err: error })
}
})
I've also tried with:
headers: {"Authorization": [API_KEY]}
data: {api_key: [API_KEY]}
Solution:
const { id } = req.body
request.get({
url: `https://a.klaviyo.com/api/v1/person/${id}`,
qs: {
api_key: process.env.KLAVIYO_API_KEY
}
}, (error, response, body) => {
const profile = JSON.parse(body)
console.log(profile)
if (response.statusCode === 200) {
res.json({ profile, status: 201 })
} else {
res.json({ error: 'Did not get customer data', status: 500, response: response, err: error })
}
})
Short answer: add it under params.api_key (as part of the GET request).
From the klaviyo documentation:
"You authenticate to the People API by providing one of your private API keys as part of each request. (...) Authentication happens via the api_key parameter in each request. It can be sent as part of the GET or POST parameters."
I think you are using GET request with POST header method. In GET you need to put it in URL