How do I add parameters to https get request? - javascript

I am working on a little project to learn how to work with APIs by making GET requests to the Twitter API v2 via a node server.
For the get requests I am using Node's built in https package.
I made a basic GET request that returns a list of the last 10 tweets from a user.
I think in order to increase the amount of tweets I can get I have to make a separate parameter object, which I then implement in the get request.
Right now my function looks like this:
function getTweets() {
const options = {
host: "api.twitter.com",
path: `/2/users/${userId}/tweets`,
headers: {
authorization:
`Bearer ${bearerToken}`,
},
};
https
.get(options, (response) => {
let data = "";
response.on("data", (chunk) => {
data += chunk;
});
response.on("end", () => {
let jsonObject = JSON.parse(data);
tweetObjects = jsonObject.data;
tweetObjects.map((item) => {
let tweetWords = "";
tweetWords += item.text;
userTweets.push(tweetWords);
});
const result = userTweets.flatMap((str) => str.split(" "));
console.log(result);
});
})
.on("error", (error) => {
console.log(error);
});
}
Right now I only have the options object with host, path, and headers in the request.
This is what I am trying to do:
function getTweets() {
const options = {
host: "api.twitter.com",
path: `/2/users/${userId}/tweets`,
headers: {
authorization:
`Bearer ${bearerToken}`,
},
};
let params = {
max_results: 100,
};
https
.get(params, options, (response) => {
let data = "";
response.on("data", (chunk) => {
data += chunk;
});
response.on("end", () => {
let jsonObject = JSON.parse(data);
tweetObjects = jsonObject.data;
tweetObjects.map((item) => {
let tweetWords = "";
tweetWords += item.text;
userTweets.push(tweetWords);
});
const result = userTweets.flatMap((str) => str.split(" "));
console.log(result);
});
})
.on("error", (error) => {
console.log(error);
});
}
But I get
throw new ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "listener" argument must be of type function. Received an instance of Object
at checkListener (events.js:131:11)
at ClientRequest.once (events.js:496:3)
at new ClientRequest (_http_client.js:215:10)
at request (https.js:326:10)
at Object.get (https.js:330:15)
at IncomingMessage.emit (events.js:388:22)
at endReadableNT (internal/streams/readable.js:1336:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21) {
code: 'ERR_INVALID_ARG_TYPE'

You can either only pass the URL or an object containing options as stated in the docs:
https://nodejs.org/api/https.html#https_https_get_url_options_callback
So you might want to try something like this:
function getTweets() {
let params = {
max_results: 100,
};
const options = {
host: "api.twitter.com",
path: `/2/users/${userId}/tweets?max_results=${params.max_results}`,
headers: {
authorization:
`Bearer ${bearerToken}`,
},
};
https
.get(options, (response) => {
let data = "";
...
}

I am not sure to understand what you are calling parameters that you want to give to the get request.
Anyway a get request does not take some body or parameter. If you want to add some data to the core of your request you have to use the post method and not the get one.
Can you show us the import of https library just to check the functions that it propose?
Best Regards,
Hugo Delatte

Related

trying to call api but its giving me connection refuse

this is my code where am using http module to call the api inside the promise but not able make
any api call its just giving 500 err
const dataString = JSON.stringify(consentDetail)
console.log("dataString",dataString)
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': dataString.length
}
}
const response = await new Promise((resolve, reject) => {
const req = https.get("URL", options, (res) => {
let finalData = "";
res.on("data", function(data){
finalData += data.toString();
})
res.on("end", () => {
var data = JSON.parse(finalData);
resolve({
statusCode: 200,
body: JSON.stringify(data, null, 2)
})
})
})
req.on('error', (err) => {
reject({
statusCode: 500,
body: err
});
})
})
return response;
and I want call the api using only http or https without having to install any npm package
There are a few things you will need to change in your code. First, the API you are calling is expecting a GET request, so you have to change that in your 'options' object. And since you're going to send a GET request, the headers 'Content-Type' and 'Content-Length' need to be removed.
Also, there is no 'url' option for the 'options' in the http module. This is why you are receiving a 500 response. Since no url/host were provided to the http module, it is attempting to connect to http://127.0.0.1:80. The correct way is to use the parameters 'host' and 'path', like this:
const options = {
host: 'catfact.ninja',
path: '/fact',
method: 'GET'
}
or include the url as the first parameter in the get method, like this:
const req = http.get('http://catfact.ninja/fact', options, (res) => {
...
}
By doing so, you will see that we now receive a new error:
undefined:1
<html>
^
SyntaxError: Unexpected token < in JSON at position 0
at JSON.parse (<anonymous>)
at IncomingMessage.<anonymous> (C:\...\index.js:18:33)
at IncomingMessage.emit (events.js:327:22)
at endReadableNT (internal/streams/readable.js:1327:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
The reason for this is that we are receiving a html response instead of a JSON. Looking further into the response, we can see that we actually received a 301 response:
HTTP/1.1 301 Moved Permanently
Server: nginx/1.20.1
Date: Wed, 29 Dec 2021 19:24:33 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://catfact.ninja/fact
The 301 redirects to the https protocol, meaning the API doesn't support http requests anymore. So let's use https instead. Just use the https built-in module instead of the http one, and change the URL to https://catfact.ninja/fact. No other changes to the code are necessary.
So, the final code should be:
const options = {
method: 'GET'
}
const response = await new Promise((resolve, reject) => {
const req = https.get('https://catfact.ninja/fact', options, (res) => {
let finalData = "";
res.on("data", function(data){
finalData += data.toString();
})
res.on("end", () => {
var data = JSON.parse(finalData);
resolve({
statusCode: 200,
body: JSON.stringify(data, null, 2)
})
})
})
req.on('error', (err) => {
reject({
statusCode: 500,
body: err
});
})
})
return response;
I think you should use https.request and options pass host and path.
check here:
https://nodejs.org/api/https.html#httpsrequestoptions-callback
const dataString = JSON.stringify(consentDetail);
console.log("dataString", dataString);
const options = {
// Update here
hostname: "hostname",
path: "/path",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": dataString.length,
},
};
const response = await new Promise((resolve, reject) => {
// update here
const req = https.request(options, (res) => {
let finalData = "";
res.on("data", function (data) {
finalData += data.toString();
});
res.on("end", () => {
var data = JSON.parse(finalData);
resolve({
statusCode: 200,
body: JSON.stringify(data),
});
});
});
req.on("error", (err) => {
reject({
statusCode: 500,
body: err,
});
});
});
return response;

Session cookie from node-fetch is invalid?

I am writing a javascript program (for a github action) right now but ran into a problem.
I was trying to log into www.overleaf.com and access the page https://www.overleaf.com/project after generating a session cookie by sending a POST request to https://www.overleaf.com/login with my credentials and the csrf token.
The response contained the requested token in the set-cookie header as expected, however, when I tried to access https://www.overleaf.com/project via GET, I get redirected back to https://www.overleaf.com/login
When copying a session cookie saved in my browser, the request works just fine as expected.
I tried doing the same thing in the command line with cURL and it worked there.
I am fairly certain my authentication request is accepted by Overleaf's server, because I have tried intentionally incorrectly sending the password or the csrf token and in both cases, the response does not give me a new session cookie but sends the old one.
If anyone has any clue what is going wrong, I'd be very thankful for your input.
This is what worked in the terminal, which I'm trying to replicate in javascript with node-fetch:
curl -v --header "Content-Type: application/json" --cookie "GCLB=someothercookie;overleaf_session2=firstsessioncookie" --data '{"_csrf":"the_csrf_token", "email": "MYEMAIL", "password":"MYPASSWORD"}' https://www.overleaf.com/login
to get the cookie and csrf token and
curl -v https://www.overleaf.com/project --cookie "overleaf_session2=returnedsessioncookie; GCLB=someothercookie" as the request that returns the html page of my projects.
This is my javascript code, I have double, triple, quadruple checked it but I think I'm missing something.
const fetch = require("node-fetch");
const parser = require("node-html-parser");
const scparser = require("set-cookie-parser");
async function run() {
const email = process.env.EMAIL;
const password = process.env.PASSWORD;
var cookies = await login(email, password);
console.log(await all_projects(cookies));
}
async function login(email, password) {
const login_get = await fetch("https://www.overleaf.com/login");
const get_cookies = login_get.headers.raw()["set-cookie"];
const parsed_get_cookies = scparser.parse(get_cookies, {
decodeValues: false
});
const overleaf_session2_get = parsed_get_cookies.find(
(element) => element.name == "overleaf_session2"
).value;
const gclb = parsed_get_cookies.find(
(element) => element.name == "GCLB"
).value;
console.log("overleaf_session2_get:", overleaf_session2_get, "gclb:", gclb);
const get_responsetext = await login_get.text();
const _csrf = parser
.parse(get_responsetext)
.querySelector("input[name=_csrf]")
.getAttribute("value");
login_json = { _csrf: _csrf, email: email, password: password };
console.log(login_json);
const login_post = await fetch("https://www.overleaf.com/login", {
method: "post",
body: JSON.stringify(login_json),
headers: {
"Content-Type": "application/json",
"Cookie": "GCLB=" + gclb + ";overleaf_session2=" + overleaf_session2_get
}
});
const post_cookies = login_post.headers.raw()["set-cookie"];
const parsed_post_cookies = scparser.parse(post_cookies, {
decodeValues: false
});
const overleaf_session2_post = parsed_post_cookies.find(
(element) => element.name == "overleaf_session2"
).value;
console.log(
"successful:",
overleaf_session2_get != overleaf_session2_post ? "true" : "false"
);
console.log(await fetch("https://www.overleaf.com/project", {
headers: {
"Cookie": "overleaf_session2=" + overleaf_session2_post
}
}))
return "overleaf_session2=" + overleaf_session2_post;
}
async function all_projects(cookies) {
const res = await fetch("https://www.overleaf.com/project", {
headers: {
Cookie: cookies
}
});
return res;
}
run();
Yes your authentication request is probably valid however this is likely to be a security issue which browsers do not allow you to do such thing and freely access another website's cookie.
Browsers do not allow you to access other domain's cookies, If they did then web would be an unsafe place because for example Stackoverflow could access my Facebook account cookie and extract my personal information.
I fixed my issue by not using node-fetch and switching to https.
Here is what worked:
async function login(email, password) {
//GET login page
const get = await get_login();
//get necessary info from response
const csrf = parser
.parse(get.html)
.querySelector(`meta[name="ol-csrfToken"]`)
.getAttribute("content");
const session1 = scparser
.parse(get.headers["set-cookie"], { decodeValues: false })
.find((cookie) => cookie.name == "overleaf_session2").value;
const gclb = scparser
.parse(get.headers["set-cookie"], { decodeValues: false })
.find((cookie) => cookie.name == "GCLB").value;
//POST login data
const post = await post_login(csrf, email, password, session1, gclb);
//get necessary data from response
const session2 = scparser
.parse(post["set-cookie"], { decodeValues: false })
.find((cookie) => cookie.name == "overleaf_session2").value;
//GET new csrf token from project page
const projects = await get_projects(session2, gclb);
const csrf2 = parser
.parse(projects.html)
.querySelector(`meta[name="ol-csrfToken"]`)
.getAttribute("content");
//return data
return {
session: session2,
gclb: gclb,
csrf: csrf2,
projects: projects.html
};
}
async function get_login() {
const url = "https://www.overleaf.com/login";
return new Promise((resolve) => {
https.get(url, (res) => {
var data;
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
resolve({ html: data, headers: res.headers });
});
});
});
}
async function get_projects(session2, gclb) {
const url = "https://www.overleaf.com/project";
return new Promise((resolve) => {
https.get(
url,
{ headers: { Cookie: `GCLB=${gclb};overleaf_session2=${session2}` } },
(res) => {
var data;
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
resolve({ html: data, headers: res.headers });
});
}
);
});
}
async function post_login(_csrf, email, password, session1, gclb) {
const url = "https://www.overleaf.com/login";
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Cookie: `GCLB=${gclb};overleaf_session2=${session1}`
}
};
const postData = {
_csrf: _csrf,
email: email,
password: password
};
return new Promise((resolve) => {
var req = https.request(url, options, (res) => {
resolve(res.headers);
});
req.on("error", (e) => {
console.error(e);
});
req.write(JSON.stringify(postData));
req.end();
});
}

how to resolve 'NodeJS API call response is an un-parsable object'?

I am getting the below result after my API call.
My node version is 12.x
{"type":"Buffer","data":[123,34,101,114,114,111,114,115,34,58,91,34,74,87,84,32,105,115,32,101,120,112,105,114,101,100,32,111,114,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,112,114,111,112,101,114,32,39,101,120,112,39,32,99,108,97,105,109,34,93,125,11]}
Please see the code snippet below:
let postOptions = {
host: 'vault.server',
path: '/v1/auth/gcp/login',
method: HTTPS.POST_REQUEST,
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-Vault-Namespace': 'mynamespace'
},
json: true,
rpDefaults: {
strictSSL: false
}
};
let requestPayLoad = {
"role": this._vaultRole,
"jwt": signedJWT
};
console.log(JSON.stringify(requestPayLoad));
console.log(JSON.stringify(postOptions));
try {
let result = await HTTPS.makeRequest(postOptions, JSON.stringify(requestPayLoad), HTTPS.POST_REQUEST);
console.log('Response***************',JSON.stringify(result));
return result.auth.client_token;
}
Please see the below code snippet for the http make request method.
return new Promise((resolve, reject) => {
let rq = https.request(options, (res) => {
let response;
let chunks = [];
res.on('data', (chunk) => {
chunks.push(chunk);
});
res.on('end', () => {
response = Buffer.concat(chunks);
return resolve(response);
});
});
rq.on('error', (e) => {
return reject({'statusCode': 500, 'success': false, 'error': e.toString()});
});
if (type === 'POST') {
rq.write(data);
}
rq.end();
});
Please help me to resolve this
You are receiving the data as a Buffer. Use the toString() method to convert this buffer into a string inside the try block.
try {
let result = await HTTPS.makeRequest(postOptions, JSON.stringify(requestPayLoad), HTTPS.POST_REQUEST);
console.log('Response***************', result.toString());
return result.auth.client_token;
}
If you want to access the data from the response returned from you API call
do:
let data = result.data;
and I you want to get client_token as showing here:
return result.auth.client_token;
it's not possible because the response does not have auth attribute on it:
{"type":"Buffer","data":[123,34,101,114,114,111,114,115,34,58,91,34,74,87,84,32,105,115,32,101,120,112,105,114,101,100,32,111,114,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,112,114,111,112,101,114,32,39,101,120,112,39,32,99,108,97,105,109,34,93,125,11]}

Adding Authorization header to GET request

I'm building an alexa skill using the new SDK 2.0 and I'm now having trouble implementing a simple http get request. How would I add an authorization header to the getRemoteData url request? The code below isn't working.
I'm trying to call Airtable API to get some remote data
const UserReplyIntent_Handler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'UserReplyIntent' ;
},
async handle(handlerInput) {
const response = await httpGet();
console.log(response);
return handlerInput.responseBuilder
.speak("Okay. Here is what I got back." + response.records.fields.Indication)
.reprompt("Would you like to learn more?")
.getResponse();
},
};
function httpGet() {
return new Promise(((resolve, reject) => {
const headers = {
Authorization: 'Bearer key12345678'
};
var options = {
host: 'api.airtable.com',
port: 443,
path: '/v0/appYqfJ3Rt2F0sRGn/Database?filterByFormula=(DrugName=%27azatadine%27)',
method: 'GET',
};
const request = https.request(options, {headers}, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}
header go into the options object, not as a separate parameter:
var options = {
host: 'api.airtable.com',
port: 443,
path: '/v0/appYqfJ3Rt2F0sRGn/Database?filterByFormula=(DrugName=%27azatadine%27)',
method: 'GET',
headers: {
Authorization: 'Bearer key12345678'
}
};
https.request accepts the same options fields as http.reqest.
http.request options object allows headers to be defined.

Access API using Node JS and parse it as a JSON file

I am trying to access all the projects from Harvest API and parse it as a JSON file. But I am new to Node JS so I do not know where to begin. Here is the link to the API documentation: Harvest API Documentation
API requires all the calls to be authenticated how can I work around that?
Thank you in Advance
You can parse using JSON.parse(data) to get the JSON Object
const https = require("https");
const options = {
protocol: "https:",
hostname: "api.harvestapp.com",
path: "/v2/users/me",
headers: {
"User-Agent": "Node.js Harvest API Sample",
Authorization: "Bearer " + process.env.HARVEST_ACCESS_TOKEN,
"Harvest-Account-ID": process.env.HARVEST_ACCOUNT_ID,
},
};
https
.get(options, (res) => {
const { statusCode } = res;
if (statusCode !== 200) {
console.error(`Request failed with status: ${statusCode}`);
return;
}
res.setEncoding("utf8");
let rawData = "";
res.on("data", (chunk) => {
rawData += chunk;
});
res.on("end", () => {
try {
const parsedData = JSON.parse(rawData);
console.log(parsedData);
} catch (e) {
console.error(e.message);
}
});
})
.on("error", (e) => {
console.error(`Got error: ${e.message}`);
});
Please refer
https://github.com/harvesthq/harvest_api_samples/blob/master/v2/harvest_api_sample.js

Categories

Resources