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

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]}

Related

How do I add parameters to https get request?

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

callback function call before calling another function

I have a function which calling one API:
const response = fetch(APIfunctonName, {
method: "POST",
body: JSON.stringify(searchRequest),
headers: {
"Content-type": "application/json; charset=UTF-8",
},
})
.then((res) => res.json())
.then(
(result) => {
let urlParams = this.getRequests();
let reqid = urlParams["requested"];
var newUrl = window.location.href
.replace(`requestID=${reqid}`, "requestID=0")
.replace("requestID=0", "requestID=" + result.RequestId); //result.RequestId always have proper one
history.pushState({}, null, newUrl);
this.getList(result.RequestId); //sometimes this goes as undefined
},
(error) => {
console.log(error);
}
);
I always get proper requested in the result object, but I don't understand why sometimes I get an old Id in the getList function
You could use a Promise as follows so that you make sure the proper request is going to be passed to next instruction :
let p = new Promise((resolve , reject) => {
let urlParams = this.getRequests();
let reqid = urlParams["requested"];
var newUrl = window.location.href
.replace(`requestID=${reqid}`, "requestID=0")
.replace("requestID=0", "requestID=" + result.RequestId);
history.pushState({}, null, newUrl);
resolve(result);
});
p.then((result) => {
this.getList(result.RequestId);
});
i think the reason is the defference between sync ajax and async ajax.
if this below ajax this.getRequests() is async. Your code will get some accidental error.
let urlParams = this.getRequests();
First solution is change async to sync.
Your can change this this.getRequests() to sync. Your code will work just fine.
Second solution is use await and async.
const response = fetch(APIfunctonName, {
method: "POST",
body: JSON.stringify(searchRequest),
headers: {
"Content-type": "application/json; charset=UTF-8",
},
})
.then((res) => res.json())
.then(
async (result) => {
let urlParams = await this.getRequests();
let reqid = urlParams["requested"];
var newUrl = window.location.href
.replace(`requestID=${reqid}`, "requestID=0")
.replace("requestID=0", "requestID=" + result.RequestId); //result.RequestId always have proper one
history.pushState({}, null, newUrl);
this.getList(result.RequestId); //sometimes this goes as undefined
},
(error) => {
console.log(error);
}
);

Fetch request not returning any data in console, or on front end

When I submit my form, I am not returning any data, not even in my console. I am trying to return details from WHOIS regarding the URL that is searched, and am getting nothing back.
Can anyone provide any advice as to why this might be the case?
Here is my front end script tag, after my form:
document.getElementById('search').addEventListener('submit', function(e) { e.preventDefault(); getDetails(); })
async function getDetails(url = `http://localhost:3000/lookup/${url}`, data = {}) {
return new Promise(function (resolve, reject) {
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'text/html'
},
body: JSON.stringify(data)
}).then(async response => {
if (response.ok) {
response.json().then(json => resolve(json))
console.log(data);
} else {
response.json().then(json => reject(json))
}
}).catch(async error => {
reject(error)
})
})
}
On my express backend I am using req.params.url if that helps provide any context at all...
My Status Code is 200, and all appears to be normal in the Headers tab...
You have a mix of promise and async syntax, which is confusing, let's translate it first by unpicking the promise and then into await (if you can use async then do, it's easer than Promise/then):
document.getElementById('search').addEventListener(
'submit',
function(e) {
e.preventDefault();
getDetails();
});
async function getDetails(url = `http://localhost:3000/lookup/${url}`, data = {})
{
// Fetch will throw an exception if it can't connect to the service
const response = await fetch(url, {
method: 'GET',
headers: { 'Content-Type': 'text/html' },
body: JSON.stringify(data)
});
if (response.ok)
return await response.json();
// We could connect but got an error back from the service
// There may not be a response body, so response.json() or .body() might crash
throw new Error(`Error from server ${response.status}: ${response.statusText}`;
// We don't need catch, as any exception in an await will cascade up anyway
}
This makes it much more readable, and it's apparent that getDetails doesn't make any changes itself, it just returns the JSON from the service. The fix needs to be in the event listener - it needs to do something with that result:
document.getElementById('search').addEventListener(
'submit',
async e => {
e.preventDefault();
const searchResult = await getDetails();
// Do something to show the results, populate #results
const resultsElement = document.getElementById('results');
resultsElement.innerText = JSON.stringify(searchResult);
});
You are mis-using async/await. Try this:
async function getDetails(url = `http://localhost:3000/lookup/${url}`, data = {}) {
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'text/html'
},
body: JSON.stringify(data)
});
const json = await response.json();
if (response.ok) {
console.log(json);
return json;
} else {
throw new Error(json);
}
}
In essence await is a replacement for then (but you can only use it in functions marked with async).

How can I redirect a URL for post request using AWS lambda?

These results are for GET and POST requests response through API gateway and lambda. used same lambda function, but when i used post method of API gateway, response just shows me JSON. what should i have to do?
when i used post req
when i used get req
it's my lambda function
exports.handler = (event, context, callback) => {
const response = {
statusCode: 301,
headers: {
Location: 'https://google.com',
}
};
return callback(null, response);
}
thank you.
I usually use the new async/await pattern when defining my aws lambdas :
exports.handler = async (event) => {
// do stuff...
}
you usually don't need the context, unless you want to use some aws-related info regarding your lambda.
I have a helper function that is re-used a lot inside the code base
function proxyResponse(inBody, inStatusCode = null, headers = {}, event = null) {
if (!isApiGateway(event)) {
if (inBody instanceof Error) {
throw inBody;
}
return inBody;
}
let statusCode = inStatusCode;
let body;
if (inBody instanceof Error) {
statusCode = statusCode || INTERNAL_SERVER_ERROR;
body = JSON.stringify({
message: inBody.message,
code: statusCode,
});
} else if (inBody instanceof Object) {
body = JSON.stringify(inBody);
} else {
body = inBody;
}
const [origin] = event ? caseHandler(event.headers, 'origin') : [];
return {
statusCode: statusCode || 200,
body,
headers: Object.assign({
'Access-Control-Allow-Headers': 'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token,x-api-key,Authorization',
'Access-Control-Allow-Origin': origin,
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT',
}, headers),
};
}
and another one :
function caseHandler(mixedCaseObject, inputKey) {
if (!mixedCaseObject || !inputKey) {
return [];
}
return Object.keys(mixedCaseObject)
.filter((key => key.toLowerCase() === inputKey.toLowerCase()))
.map(key => mixedCaseObject[key]);
}
and this one :
function isApiGateway(event) {
return (!!event.httpMethod && !!event.headers && !!event.requestContext);
}
so inside the lambda whenever I want to return something I use this helper functions :
module.exports.handler = async (event) => {
try{
// do stuff...
return proxyResponse(YOUR_CUSTOM_BODY_OBJECT, Api.HTTP.OK, {}, event);
} catch(error) {
return proxyResponse(error, Api.HTTP.INTERNAL_SERVER_ERROR, {}, event);
}
}
The GET request will return any content provided in the response. In this case, it is the JSON object response. For POST requests the same response object is being returned back to the API Gateway which is then returning it back as-is to the client.
Perhaps the documentation here could be of help https://docs.aws.amazon.com/en_pv/apigateway/latest/developerguide/api-gateway-integration-settings-integration-response.html

Reading value from JSON array in Node.js during Get request

I need to pull the Indication value from the following array
{
"records": [{
"id": "recBgV3VDiJeMkcwo",
"fields": {
"DrugName": "azatadine",
"nameapi": ["recBgV3VDiJeMkcwo"],
"Indication": "For the relief of the symptoms of upper respiratory mucosal congestion in perennial and allergic rhinitis, and for the relief of nasal congestion and eustachian t.b. congestion.",
"lookup": ["azatadine"],
"drugID": "recBgV3VDiJeMkcwo"
},
"createdTime": "2018-11-09T19:38:24.000Z"
}]
}
When I try to do response.records.fields[0]["Indication"] I get undefined.
Here is my full code:
function httpGet() {
return new Promise(((resolve, reject) => {
var options = {
host: 'api.airtable.com',
port: 443,
path: '/v0/appYqfJ3Rt2F0sRGn/Database?filterByFormula=(DrugName=%27azatadine%27)',
method: 'GET',
headers: {
Authorization: 'Bearer key123456789'
}
};
const request = https.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(returnData);
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}
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 we go" + response.records[0].fields.Indication)
.reprompt("say again")
.getResponse();
},
};
Thanks in advance for your help.
it should be response.records[0].fields.Indication
Fields doesn't look like an array. Try response.records.fields.Indication
Show console.log(response) output. Looks like that you made a mistake in getting a response

Categories

Resources