Javascript REST API - You must specify an API key to make request - javascript

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

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

How to pass jwt token from controller to router using NodeJS

Hello developers the question is simple,
I have generated a jwt token in my Login function using the jwt.sign(), and I have Model/Controller/Router Architecture,
so the question is : How can I pass the generated token from the Login controller function to the router.
I've tried many times to assign the token to a const variable to send it throw an object and send it to the router files, but when I go out from the jwt.sign() function it shows me that is undefined.
PS : I'am just using NodeJS and fastify in the backend and send http request with Postman am not using any framework in the front-end
There is some code than can help you to understand my situation :
UserRouter.js: (Login route) :
{
method: "POST",
url: "/api/login",
handler: (req, res) => {
UserController.login(req.body.email, req.body.password)
.then(result => {
//res.header("Access-Control-Allow-Origin", URL);
if (result.statusCode == 200) {
res.send({
status: 200,
error: null,
response: result.Message
//token: result.token
});
} else if (result.statusCode == 401) {
res.send(
JSON.stringify({
status: 401,
error: null,
response: result.Message
})
);
}
})
.catch(err => {
//res.header("Access-Control-Allow-Origin", URL);
res.send(JSON.stringify({ status: 300, error: err, response: null }));
});
}
}
User Controller :
exports.login = async (user_email, password) => {
try {
console.log("Login into API");
const email = user_email.toLowerCase();
const user = await User.findOne({ email });
if (user) {
console.log(" Hashed Passwd ", user.password);
console.log("User Passwd", password);
let result = await bcrypt.compareSync(password, user.password);
if (result) {
// Tryed also with const = await jwt.sign()
jwt.sign({ user }, "secretkey", (err, token) => {
if (err) throw err;
console.log("The Token is", token);
});
return {
Message: "Login success",
statusCode: 200
//token: token
};
} else {
return { Message: "Incorrect password", statusCode: 401 };
}
} else {
return { Message: "ERROR" };
}
} catch (err) {
throw boom.boomify(err);
}
};
if you look at the package readme, you'll find jwt.sign returns nothing when a callback is provided.
So what you should do is:
const token = jwt.sign({ user }, "secretkey");
That would make the library work synchronously and return the token.

MailChimp Error Status: 401 Title: "API Key Invalid"

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...

res.send is not returning the expected data: JavaScript, Express, Node?

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

NodeJs - fetch request from client always returns a 200 status response from the server regardless if there was an error updating the DB

I am using a fetch() request from the client to PUT updated user data to the backend, to then be saved into a DB. So far, the all of the route is working fine, verified and tested in Postman.
In this User Update route, there is an if statement that checks for an error when searching for the user in the database, and if this error is thrown, it sends a response of 404 and a message to the client.
When I make the fetch() request from the client to this route, regardless if there is an error, the response is always a status 200, and does not include any response from my route. I need the client to be able to handle the potential errors the routes might produce. For example with this user update route, if the user is not found in the database for whatever reason, an error and message is returned, so the client needs to know this.
Here is some code:
Client-side:
fetch(`http://localhost:3000/users/${userId}`, {
method: "put",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(userData)
}).then(response => console.log(response))
.catch(err => console.log(err));
Here in the client, I am using console.log() to visualize everything. When the response returns, I get back:
Response {type: "basic", url: "http://localhost:3000/users/accounts/", redirected: false, status: 200, ok: true, …}
Server-side route controller:
exports.user_update = (req, res) => {
const { params, body } = req;
const { userid } = params;
User.findByIdAndUpdate({ _id: userid }, body, { new: true }, (err, user) => {
if (err)
res.send({
status: 404,
message:
"There was an issue finding and updating the user on the server."
});
else
res.send({
status: 200,
user
});
});
};
Now here on the server, I anticipated the response of the fetch() to be either the 404 error or the 200 success along with their payloads. Neither are returned in a response from the server. Instead as mentioned above, I am getting a generic 200 ok response simply letting me know the fetch() made a connection to the route. This route(along with the others) has been tested in Postman, and all work as anticipated returning the expected responses.
What am I not understanding here? Is my idea of using a fetch() request in this manner wrong? I feel like I might be close, but that's just my ignorant guess. Thank for reading!
I figured out the solution.
The fetch request was wrong, here is the update:
fetch(`http://localhost:3000/users/${userId}`, {
method: "put",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(userData)
}).then(response => response.json())
.then(response => console.log(response))
.catch(err => console.log(err));
I had to call response.json() to parse the response as a JSON object.
According to express documentation you sent status as a field of JSON. To correctly send http status replace your res.send(...) with
res.status(404).send("There was an issue finding and updating the user on the server.");
and
res.send(user);
You are sending the status field inside your payload, which is not parsed by fetch API.
To solve this you could something as below
exports.user_update = (req, res) => {
const { params, body } = req;
const { userid } = params;
User.findByIdAndUpdate({ _id: userid }, body, { new: true }, (err, user) =>
{
if (err)
res.status(404).send({
message: "There was an issue finding and updating the user on the server."
});
else
res.status(200).send({
user
});
});
};

Categories