Error while calling api using node.js - javascript

I am Calling an API with with following with Node.js code but the code is always throwing an error.
Basically I am creating a bot with Microsoft Bot Framework and throwing an image to the API and evalutaing the response
var restify = require('restify');
var builder = require('botbuilder');
var http = require("http");
var request= require("request");
var rest = require('rest');
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () { });
// Create the chat connector for communicating with the Bot Framework Service
var connector = new builder.ChatConnector({
appId: 'APP_ID',
appPassword: 'APP_PASS'
});
// Listen for messages from users
server.post('/api/messages', connector.listen());
server.get('/', restify.plugins.serveStatic({
directory: __dirname,
default: '/index.html'
}));
var bot = new builder.UniversalBot(connector, function (session, results) {
var attachment = session.message.attachments[0];
request({url: attachment.contentUrl, encoding: null}, function (error, response, body) {
// Take the image and post to the custom vision service
rest.post('URL_OF_API' , {
multipart: true,
headers: {
'Prediction-Key': 'KEY',
'Content-Type': 'multipart/form-data'
},
data: {
'filename': rest.data('TEST.png', 'image/png', body)
}
}).on('complete', function(data) {
let men = 0.0; //not-men
let women = 0.0; //not-women
let topHit = { Probability: 0.0, Tag: '' };
for (var i = 0; i < data.Predictions.length; i++) {
if (data.Predictions[i].Tag === 'Men')
men = data.Predictions[i].Probability;
else if (data.Predictions[i].Tag === 'Women')
women = data.Predictions[i].Probability;
else {
if (data.Predictions[i].Probability > topHit.Probability)
topHit = data.Predictions[i];
}
}
let gender = 'No idea';
if (men > women)
gender = 'Men';
if (women > men)
gender = 'Women';
var opt='The Pic sent appears to be a'+gender+'or'+gender+'s cloth';
session.endDialog(opt);
}).on('error', function(err, response) {
session.send('Error calling custom vision endpoint');
}).on('fail', function(data, response) {
session.send('Failure calling custom vision endpoint');
});
});
});
I am getting this error
'filename': rest.data('TEST.png', 'image/png', body)
^
TypeError: rest.data is not a function
at Request._callback (C:\Users\Tushar\botforarticle\app.js:39:26)
at Request.self.callback (C:\Users\Tushar\botforarticle\node_modules\request\request.js:188:22)
at emitTwo (events.js:106:13)
at Request.emit (events.js:191:7)
at Request.<anonymous> (C:\Users\Tushar\botforarticle\node_modules\request\request.js:1171:10)
at emitOne (events.js:96:13)
at Request.emit (events.js:188:7)
at IncomingMessage.<anonymous> (C:\Users\Tushar\botforarticle\node_modules\request\request.js:1091:12)
at IncomingMessage.g (events.js:291:16)
at emitNone (events.js:91:20)

That's because, well, rest.data is indeed not a function.
See the docs:
https://github.com/cujojs/rest
It's not very clear what are you trying to do here, why are you doing it that way and what have you tried to fix the issue. With more context it would be easier to give you a more specific answer but without enough information all I can tell you is to read the documentation of the module that you're using or to use some other module that may better suit your needs, like request, restler, unirest, superagent or some other HTTP/REST client available in Node.

Related

Sending request to webserver using axios

I want to send an array of strings over localhost 3000 with route start then send back a response with status 200 and eventually a map attached to response.body Currently i have this
Client code:
const axios = require('axios');
let listOfNames = ['mikey'];
axios.post(''http://localhost:3000/start'', {
data: { names: listOfNames }
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Server code:
const express = require('express');
const app = express()
const port = 3000
var listOfNames = [];
app.post('/start', async (req, res) => {
listOfNames = req.params.listOfNames;
res.status(200).send("Names added");
});
app.listen(port, () => {
console.log('request recieved');
});
I get this error presemably from how the request is being sent, any help?
TypeError [ERR_INVALID_URL]: Invalid URL
at new NodeError (node:internal/errors:393:5)
at URL.onParseError (node:internal/url:565:9)
at new URL (node:internal/url:645:5)
at dispatchHttpRequest (C:\Users\cmb\rectangleHealth\node_modules\axios\dist\node\axios.cjs:23
94:20)
at new Promise (<anonymous>)
at http (C:\Users\cmb\rectangleHealth\node_modules\axios\dist\node\axios.cjs:2330:10)
at Axios.dispatchRequest (C:\Users\cmb\rectangleHealth\node_modules\axios\dist\node\axios.cjs:
3260:10)
at Axios.request (C:\Users\cmb\rectangleHealth\node_modules\axios\dist\node\axios.cjs:3610:33)
at Axios.httpMethod [as post] (C:\Users\cmb\rectangleHealth\node_modules\axios\dist\node\axios
.cjs:3649:19)
at Function.wrap [as post] (C:\Users\cmb\rectangleHealth\node_modules\axios\dist\node\axios.cj
s:27:15) {
input: '/start',
code: 'ERR_INVALID_URL'
}
Edit: New error ECONNRESET error emerging from applied fixes
AxiosError: read ECONNRESET
at AxiosError.from (C:\Users\cmb\rectangleHealth\node_modules\axios\dist\node\axios.cjs:789:14
)
at RedirectableRequest.handleRequestError (C:\Users\cmb\rectangleHealth\node_modules\axios\dis
t\node\axios.cjs:2744:25)
at RedirectableRequest.emit (node:events:513:28)
at eventHandlers.<computed> (C:\Users\cmb\rectangleHealth\node_modules\follow-redirects\index.
js:14:24)
at ClientRequest.emit (node:events:513:28)
at Socket.socketErrorListener (node:_http_client:494:9)
at Socket.emit (node:events:513:28)
at emitErrorNT (node:internal/streams/destroy:151:8)
at emitErrorCloseNT (node:internal/streams/destroy:116:3)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
syscall: 'read',
code: 'ECONNRESET',
errno: -4077,
The console also outputs a 2 json objects called request and config that cannot fit into this post.
I noticed 2 things errors in your code:
First, check your url is correct, instead of
''http://localhost:3000/start'' (you have multiple single quotes wrapping the url)
try,
"http://localhost:3000/start" or 'http://localhost:3000/start' (wrap it in proper double quotes or single quotes)
Second, You are passing the data in your api call as request body and not as request parameters, but you are trying to access it in the parameters of your api.
You should try accessing the request's body on the server side instead of parameters,
app.post('/start', async (req, res) => {
listOfNames = req.body.listOfNames;
res.status(200).send("Names added");
});
Else you might probably face issue while accessing the data in api as well.

google fit rest api redirection url is returning FetchError: request to https://oauth2.googleapis.com/token failed, reason: connect ECONNREFUSED

I am trying to build a project in which I will fetch the user's step count by using the google fit Rest API. For this, I have created a project on google's developer console and specified a redirection url there. Have a look to the code snippet below :
exports.getUrl = async (req, res, next) => {
try {
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_FIT_CLIENT_ID,
process.env.GOOGLE_FIT_CLIENT_SECRET,
process.env.GOOGLE_FIT_REDIRECTION_URL
);
console.log("oauth2Client", oauth2Client)
// generate a url that asks permissions for fitness activity scopes
const scopes = ["https://www.googleapis.com/auth/fitness.activity.read profile email openid"];
const url = oauth2Client.generateAuthUrl({
access_type: "offline",
scope: scopes,
include_granted_scopes: true,
state: JSON.stringify({
// callbackurl: req.body.callbackurl,
})
});
console.log("url", url);
var options = {
url: url,
proxy: 'http://proxy-url:port'
}
request(options, (err, response, body) => {
if (response) {
console.log("statuscode ", response && response.statusCode);
//res.status(200).send(url);
res.redirect(url);
} else {
console.log("err", err)
res.status(500).send(err);
}
});
} catch (err) {
console.log("err", err)
next(err);
}
}
exports.getSteps = async (req, res, next) => {
try {
const queryUrl = new urlParse(req.url);
const code = queryParse.parse(queryUrl.query).code;
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_FIT_CLIENT_ID,
process.env.GOOGLE_FIT_CLIENT_SECRET,
process.env.GOOGLE_FIT_REDIRECTION_URL
);
const token = await oauth2Client.getToken(code);
oauth2Client.setCredentials(token);
const result = await axios({
proxy: {
protocol: 'http',
host: 'proxy-url',
port: port
},
method: "POST",
headers: {
authorization: "Bearer " + token.tokens.access_token
},
"Content-Type": "application/json",
url: "https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate",
data: {
"aggregateBy": [{
"dataTypeName": "com.google.step_count.delta",
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"
}],
"bucketByTime": { "durationMillis": 86400000 }, // This is 24 hours
"startTimeMillis": startTime, // This startTime and endTime I am getting from DB
"endTimeMillis": endTime
}
});
if (result) {
const response = [];
let stepArray = result?.data?.bucket;
for (const dataSet of stepArray) {
for (const points of dataSet.dataset) {
for (const steps of points.point) {
response.push(steps?.value[0]?.intVal);
}
}
}
res.status(200).send(response);
} else {
throw new Error('Data fetching failed!');
}
} catch (err) {
next(err);
}
}
The steps url is what I have mentioned as a redirection url on the google's developer console. I have used proxy because the urls which are getting called are not whitelisted on the server on which I am deploying the code.
Now, everything worked perfectly fine in localhost but on server, I am getting below error :
FetchError: request to https://oauth2.googleapis.com/token failed, reason: connect ECONNREFUSED 172.217.167.234:443
    at ClientRequest.<anonymous> (/home/node/app/node_modules/node-fetch/lib/index.js:1491:11)
    at ClientRequest.emit (node:events:394:28)
    at TLSSocket.socketErrorListener (node:_http_client:447:9)
    at TLSSocket.emit (node:events:394:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)
This error in coming in the steps api call. I have tried to set the proxy options like below but still same error.
google.options({
proxy: 'http://proxy-url:port'
})
I have tried to use the https-proxy-agent and http-proxy-agent too but no outcome.
Also, one thing to note here is that the above error is coming when I am trying to get the data from chrome with --disable-web-security flag otherwise the first the route which is url itself is not working and throwing timeout error.
Please let me know if I am doing something wrong. Any response would be highly appreciated.

The "chunk" argument must be of type string or an instance of Buffer

I'm running the following code and it fails with the below error.
AWS Code to list all objects inside a bucket.
const http = require('http');
const host = '127.0.0.1';
const port = 5000;
const path = require('path');
const url = require('url');
const fs = require('fs');
var AWS = require('aws-sdk');
const laptopDate = JSON.parse(fs.readFileSync(`${__dirname}/data/data.json`, `utf-8`));
AWS.config.update({accessKeyId: '***', secretAccessKey: '***', region: 'ap-south-1'});
s3 = new AWS.S3({apiVersion: '2006-03-01'});
var params = {
Bucket: 'bucket-name'
};
const server = http.createServer(function(req, res){
const path = url.parse(req.url, true).pathname;
const id = url.parse(req.url, true).query.id;
if (path === 'bucket' || path === '/')
s3.listObjects(params, function (err, data) {
if(err) throw err;
res.writeHead(200, { 'Content-Type': 'text/html' });
//const output = JSON.parse(data)
console.log(data);
res.end(data);
});
});
server.listen(port, host, function(req, res) {
console.log(`Server is listening on ${host} and ${port}`)
});
The first output which is console.log displays everything as expected.
However the res.end to render the output to the screen fails with the below error.
The "chunk" argument must be of type string or an instance of Buffer. Received an instance of Object
at ServerResponse.end (_http_outgoing.js:752:13)
at Response.<anonymous> (D:\js\Extra\starter\index.js:30:13)
at Request.<anonymous> (D:\js\Extra\starter\node_modules\aws-sdk\lib\request.js:364:18)
at Request.callListeners (D:\js\Extra\starter\node_modules\aws-sdk\lib\sequential_executor.js:106:20)
at Request.emit (D:\js\Extra\starter\node_modules\aws-sdk\lib\sequential_executor.js:78:10)
at Request.emit (D:\js\Extra\starter\node_modules\aws-sdk\lib\request.js:683:14)
at Request.transition (D:\js\Extra\starter\node_modules\aws-sdk\lib\request.js:22:10)
at AcceptorStateMachine.runTo (D:\js\Extra\starter\node_modules\aws-sdk\lib\state_machine.js:14:12)
at D:\js\Extra\starter\node_modules\aws-sdk\lib\state_machine.js:26:10
at Request.<anonymous> (D:\js\Extra\starter\node_modules\aws-sdk\lib\request.js:38:9) {
message: 'The "chunk" argument must be of type string or an instance of Buffer. Received an instance of Object',
code: 'ERR_INVALID_ARG_TYPE',
time: 2020-05-18T08:39:24.916Z
}
Remove this res.writeHead(200, { 'Content-Type': 'text/html' });
And instead of res.end(data) use res.send(data) or better yet res.send({ data }).
EDIT
I didn't notice that you didn't use express, try this:
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify(data));
res.end();
In case this may help someone, try to use the objectMode propertie.
somthing like it
const t = new Transform({
objectMode: true, // set this one to true
transform(data, _, done) {
//...your code
}
});
In case this may help someone, I was using data type other than String, Number to be exact, so I changed it to String to resolve this error

Node http request under IIS Node failing against Azure CORS webservice - getaddrinfo ENOTFOUND

When running purely under node everything works perfectly, as soon as I try to run under IIS Node, the Node http request fails every time with ENOTFOUND on getaddrinfo. This is part of a mid sized website with everything else working under Node and IIS Node, just this request to an Azure CORS web service is failing. I also have similar web service requests to google maps that work perfectly in both environments. Both the google maps and the Azure web service calls use the same shared code to handle the request.
// Simplified
//==================================
var http = require("http")
var options = {
host: "xxx.azurewebsites.net",
path: "/address?postcode=SL6+1PB",
headers: {
"SerialNo": "xxx",
"RegKey": "xxx",
"Company": "xxx"
}
};
req = https.request(options, callback);
req.end();
// The Whole thing
//===========================
function getData(host, port, path, headers, data, secure) {
return new promise(function(resolve, reject) {
var options = {}, req;
try {
options.host = host;
if(!!port) {options.port = port;}
if(!!data) {options.method = "POST";}
if(!!path) {options.path = path.replace(/\s+/g, "+");}
if(!!headers) {options.headers = headers;}
if(!!secure) {req = https.request(options, callback);}
else {req = http.request(options, callback);}
req.on("error", function(error) {
rejectPromise(reject, error, "datahttp.getData");
});
if(!!data) {req.write((typeof(data) === "object" ? JSON.stringify(data) : data));}
req.end();
}
catch(error) {
// This error object drops the message property on stringify
error = {method: "datahttp.getData", success: false, message: error.message};
rejectPromise(reject, error, "datahttp.getData");
}
function callback(response) {
var str = "";
//another chunk of data has been received, so append it to `str`
response.on("data", function(chunk) {
str += String(chunk);
});
// the whole response has been received
response.on("end", function () {
if(response.statusCode == 200) {
try {
switch(response.headers["content-type"].split(";")[0]) {
case "application/xml":
xmlToJSN(str)
.then(function(result) {
resolve({method: "datahttp.getData", success: true, data: result});
})
.catch(function(error) {
rejectPromise(reject, error, "datahttp.getData");
});
break;
case "application/json":
resolve({method: "datahttp.getData", success: true, data: JSON.parse(str)});
break;
default:
resolve({method: "datahttp.getData", success: true, data: str});
}
}
catch(error) {
rejectPromise(reject, error, "datahttp.getData");
}
}
else {
rejectPromise(reject, {message: response.statusMessage + " (" + response.statusCode + ")"}, "datahttp.getData");
}
});
response.on("error", function(error) {
rejectPromise(reject, error, "datahttp.getData");
});
}
});
}
I have been struggling with this for a few days and clearly just not seeing something very obvious, some help and a smack upside the head would be welcome
Stack Trace
====================
Trace: { [Error: getaddrinfo ENOTFOUND daaddressing-prod-ne.azurewebsites.net/ daaddressing-prod-ne.azurewebsites.net/:80]
code: 'ENOTFOUND',
errno: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'daaddressing-prod-ne.azurewebsites.net/',
host: 'daaddressing-prod-ne.azurewebsites.net/',
port: 80 }
at ClientRequest.<anonymous> (C:\Dev\Node\acinet_flint\server\datahttp.js:47:29)
at emitOne (events.js:77:13)
at ClientRequest.emit (events.js:169:7)
at Socket.socketErrorListener (_http_client.js:269:9)
at emitOne (events.js:77:13)
at Socket.emit (events.js:169:7)
at connectErrorNT (net.js:1012:8)
at nextTickCallbackWith2Args (node.js:442:9)
at process._tickCallback (node.js:356:17)
{ [Error: getaddrinfo ENOTFOUND daaddressing-prod-ne.azurewebsites.net/ daaddressing-prod-ne.azurewebsites.net/:80]
code: 'ENOTFOUND',
errno: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'daaddressing-prod-ne.azurewebsites.net/',
host: 'daaddressing-prod-ne.azurewebsites.net/',
port: 80,
service: 'acinet',
success: false,
method: 'datahttp.getData' }

Can't set headers after they are sent after setting the content-type

I am trying to get an object from my server API.
This API has it as a stream.
I can get its mime thanks to its key (which ends by .jpg etc...).
I would like to send back a content-type with the right type-mime and not always with application/octet-stream.
I found in npm mime which does the work but when I go to the url http://localhost:3000/file/myb/userId/test.jpeg the server shutdown and throw :
http.js:691
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:691:11)
at ServerResponse.res.setHeader (D:\Utilisateurs\A579871\Documents\GIT\shb- gitrepository-1\node_modules\express\node_modules\connect\lib\patch.js:63:22)
at ServerResponse.<anonymous> (D:\Utilisateurs\A579871\Documents\GIT\shb-gitrepository-1\node_modules\express\node_modules\connect\lib\patch.js:80:14)
at Array.forEach (native)
at ServerResponse.res.writeHead (D:\Utilisateurs\A579871\Documents\GIT\shb-gitrepository-1\node_modules\express\node_modules\connect\lib\patch.js:79:28)
at IncomingMessage.<anonymous> (D:\Utilisateurs\A579871\Documents\GIT\shb-gitrepository-1\server.js:49:17)
at IncomingMessage.EventEmitter.emit (events.js:95:17)
at IncomingMessage.<anonymous> (_stream_readable.js:746:14)
at IncomingMessage.EventEmitter.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:408:10)
I found this topic about the subject and tried to use the advices without finding the solution
Error: Can't set headers after they are sent to the client
Here is my code :
var express = require('express');
var http = require('http');
var mime = require('mime');
var app = express();
var maxAge = 31557600000;
var port = 3000;
app.use(express.static(__dirname + '/app'));
app.get('/file/:bId/:userId/:fileKey', function(req, res) {
var headersGet = {
'auth-format': 'UID',
'Authorization': req.params.userId
};
var optionsGet = {
host: 'localhost',
port: 5000,
path: '/' + req.params.bId + '/' + req.params.fileKey,
method: 'GET',
headers: headersGet
};
var reqGet = http.request(optionsGet, function(resGet) {
resGet.on('data', function(d) {
type = mime.lookup(req.params.fileKey);
var charset = mime.charsets.lookup(type);
var newHead = {};
if (charset) {
newHead = {
"Content-Type": type
};
} else {
newHead = {
"Content-Type": type,
"charset": charset
};
}
res.writeContinue();
res.writeHead(200, newHead);
res.write(d);
res.end(d);
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.error(e);
});
});
app.listen(port);
console.log('Listening on port ' + port);
The major problem here is that you must not assume you will always get a single 'data' event. Instead, write the header once (use a boolean guard variable if you want to do this in a 'data' event so that it only gets done once), write the data, and on resGet's 'end' event, end the response.
OR: write the header (outside of the 'data' event) and just resGet.pipe(res);, removing the resGet's 'data' and 'end' event handlers entirely.

Categories