Passing data from vendor API to client side for processing - node.js

I have a bog standard nodejs and express app. I then have a 3rd party API call (https://github.com/agilecrm/nodejs) that has a set function to collect the data I require. Normally, with an DB call, I am fine, where I call the data return it via res.json(data) and and its available client side in the public folder from express, but I seem to really be struggling with the format of the 3rd party function to get the data to return so I can collect it client side.
Here is an example of the api call:
var AgileCRMManager = require("./agilecrm.js");
var obj = new AgileCRMManager("DOMAIN", "KEY", "EMAIL");
var success = function (data) {
console.log(data);
};
var error = function (data) {
console.log(data);
};
obj.contactAPI.getContactsByTagFilter('tester tag',success, error);
This works fine to console the data, but I need to get it client side so I can use it in the front end, and the only method I know is via routing, how would I achieve this, or is there a better method? Its the fact where the data runs via the 2nd element in the function, that I can't get in my response in the various methods I have tried.
app.get('/get_contacts_by_tag', function (req, res) {
obj.contactAPI.getContactsByTagFilter('Confirmed', success, error);
var success = function (data) {
res.json(data);
};
});
Any help would be greatly appreciated.

You didn't define the error callback and also you assign the success callback after the api call.
app.get('/get_contacts_by_tag', function (req, res) {
var success = function (data) {
res.json(data);
};
var error = function (data) {
res.status(500).json(data);
};
obj.contactAPI.getContactsByTagFilter('Confirmed', success, error);
});

Related

How to evaluate API response from server and act accordingly at client side using Fetch() and Node.js

I fetch data at server side and push the result to global variable and then send that global variable to client with app.post method using Express.js. My problem is that client fetches the global variable too soon without the data received from the API first. How can I evaluate the response so that client would wait the global variable to reveive data first before displaying anything.
Server side, code looks something like this:
let sharpe = ''
app.post('/api', async(req, res, next) => {
console.log('I got a request!')
thisOne = req.body.stock1
thisOne2 = req.body.stock2
var result = await setup();
res.json({
status: 'success',
stocks: sharpe
});
})
Sharpe is the global variable storing the response from multiple API calls and is the one that should be sent back to client. Client side code is this:
const sendData = async (event) => {
event.preventDefault();
var stock1 = document.getElementById('weight1').value
var stock2 = document.getElementById('weight2').value
const data = {stock1, stock2};
const options = {
method: 'POST',
body: JSON.stringify(data),
headers: {'Content-Type': 'application/json' }
}
fetch('/api', options).then(res => res.json()).then(res => {
console.log(res.stocks);
})
}
As a result SendData() function fetches the sharpe variable that is empty at the moment. How can I adjust client side code or server side code that the client waits for a correct response? Thanks.
One solution would be to store the API results to database and client would fetch ready made datastream but is there more straightforward solution?
To wait for your API Server to set the sharpe Parameter, it needs to be awaited, which you already did. It depends on the setup function (for example setup()) which fills the sharpe parameter. It has to return a promise, which is resolved once sharpe is filled with the data.
let sharpe = ''
async setup() {
return new Promise((resolve, reject) => {
sharpe = 'test';
// set value for sharpe
resolve()
})
}
app.post('/api', async(req, res, next) => {
console.log('I got a request!')
thisOne = req.body.stock1
thisOne2 = req.body.stock2
var result = await setup();
res.json({
status: 'success',
stocks: sharpe
});
})
Eventually it starded working when I pushed all the API calls in the app.post middleware at the server side using promise chaining. The initial problem remains a mystery.

How to Store an respone into a variable nodejs request module

I am trying to store the response of an http request made using nodejs by request module but the problem is I can't acsess it after the request is completed in more details we can say after the callback
How I can add it
Here is what I tried till now
Tried to use var instead of let
Tried passing it to a function so that i can use it later but no luck
Here is my code can anyone help actually new to nodejs that's why maybe a noob question
var request = require('request')
var response
function sort(body) {
for (var i = 0; i < body.length; i++) {
body[i] = body[i].replace("\r", "");
}
response = body
return response
}
request.get(
"https://api.proxyscrape.com/?request=getproxies&proxytype=http&timeout=10000&country=all&ssl=all&anonymity=all",
(err, res, body) => {
if (err) {
return console.log(err);
}
body = body.split("\n");
sort(body);
}
);
console.log(response)
In this I am fetching up the proxies from this api and trying to store them in a variable called as response
var request = require("request");
var response;
async function sort(body) {
await body.split("\n");
response = await body;
console.log(response); // this console log show you after function process is done.
return response;
}
request.get(
"https://api.proxyscrape.com/?request=getproxies&proxytype=http&timeout=10000&country=all&ssl=all&anonymity=all",
(err, res, body) => {
if (err) {
return console.log(err);
}
sort(body);
}
);
// console.log(response); //This console log runs before the function still on process, so that's why it gives you undefined.
Try this code it works fine I just tested.
put the console log inside the function so you can see the result.
The console.log that you put actually runs before you process the data so that's why you are getting "undefined".
Actually, you will get the data after the sort Function is done processing.

Nodejs global variable scope issue

I'm quite new to Nodejs. In the following code I am getting json data from an API.
let data_json = ''; // global variable
app.get('/', (req, res) => {
request('http://my-api.com/data-export.json', (error, response, body) => {
data_json = JSON.parse(body);
console.log( data_json ); // data prints successfully
});
console.log(data_json, 'Data Test - outside request code'); // no data is printed
})
data_json is my global variable and I assign the data returned by the request function. Within that function the json data prints just fine. But I try printing the same data outside the request function and nothing prints out.
What mistake am I making?
Instead of waiting for request to resolve (get data from your API), Node.js will execute the code outside, and it will print nothing because there is still nothing at the moment of execution, and only after node gets data from your api (which will take a few milliseconds) will it execute the code inside the request. This is because nodejs is asynchronous and non-blocking language, meaning it will not block or halt the code until your api returns data, it will just keep going and finish later when it gets the response.
It's a good practice to do all of the data manipulation you want inside the callback function, unfortunately you can't rely on on the structure you have.
Here's an example of your code, just commented out the order of operations:
let data_json = ''; // global variable
app.get('/', (req, res) => {
//NodeJS STARTS executing this code
request('http://my-api.com/data-export.json', (error, response, body) => {
//NodeJS executes this code last, after the data is loaded from the server
data_json = JSON.parse(body);
console.log( data_json );
//You should do all of your data_json manipluation here
//Eg saving stuff to the database, processing data, just usual logic ya know
});
//NodeJS executes this code 2nd, before your server responds with data
//Because it doesn't want to block the entire code until it gets a response
console.log(data_json, 'Data Test - outside request code');
})
So let's say you want to make another request with the data from the first request - you will have to do something like this:
request('https://your-api.com/export-data.json', (err, res, body) => {
request('https://your-api.com/2nd-endpoint.json', (err, res, body) => {
//Process data and repeat
})
})
As you can see, that pattern can become very messy very quickly - this is called a callback hell, so to avoid having a lot of nested requests, there is a syntactic sugar to make this code look far more fancy and maintainable, it's called Async/Await pattern. Here's how it works:
let data_json = ''
app.get('/', async (req,res) => {
try{
let response = await request('https://your-api.com/endpoint')
data_json = response.body
} catch(error) {
//Handle error how you see fit
}
console.log(data_json) //It will work
})
This code does the same thing as the one you have, but the difference is that you can make as many await request(...) as you want one after another, and no nesting.
The only difference is that you have to declare that your function is asynchronous async (req, res) => {...} and that all of the let var = await request(...) need to be nested inside try-catch block. This is so you can catch your errors. You can have all of your requests inside catch block if you think that's necessary.
Hopefully this helped a bit :)
The console.log occurs before your request, check out ways to get asynchronous data: callback, promises or async-await. Nodejs APIs are async(most of them) so outer console.log will be executed before request API call completes.
let data_json = ''; // global variable
app.get('/', (req, res) => {
let pr = new Promise(function(resolve, reject) {
request('http://my-api.com/data-export.json', (error, response, body) => {
if (error) {
reject(error)
} else {
data_json = JSON.parse(body);
console.log(data_json); // data prints successfully
resolve(data_json)
}
});
})
pr.then(function(data) {
// data also will have data_json
// handle response here
console.log(data_json); // data prints successfully
}).catch(function(err) {
// handle error here
})
})
If you don't want to create a promise wrapper, you can use request-promise-native (uses native Promises) created by the Request module team.
Learn callbacks, promises and of course async-await.

node.js server and AWS asynchronous call issue

I have a simple node Express app that has a service that makesa call to a node server. The node server makes a call to an AWS web service. The AWS simply lists any S3 buckets it's found and is an asynchronous call. The problem is I don't seem to be able to get the server code to "wait" for the AWS call to return with the JSON data and the function returns undefined.
I've read many, many articles on the web about this including promises, wait-for's etc. but I think I'm not understanding the way these work fully!
This is my first exposer to node and I would be grateful if somebody could point me in the right direction?
Here's some snippets of my code...apologies if it's a bit rough but I've chopped and changed things many times over!
Node Express;
var Httpreq = new XMLHttpRequest(); // a new request
Httpreq.open("GET","http://localhost:3000/listbuckets",false);
Httpreq.send(null);
console.log(Httpreq.responseText);
return Httpreq.responseText;
Node Server
app.get('/listbuckets', function (req, res) {
var bucketData = MyFunction(res,req);
console.log("bucketData: " + bucketData);
});
function MyFunction(res, req) {
var mydata;
var params = {};
res.send('Here are some more buckets!');
var request = s3.listBuckets();
// register a callback event handler
request.on('success', function(response) {
// log the successful data response
console.log(response.data);
mydata = response.data;
});
// send the request
request.
on('success', function(response) {
console.log("Success!");
}).
on('error', function(response) {
console.log("Error!");
}).
on('complete', function() {
console.log("Always!");
}).
send();
return mydata;
}
Use the latest Fetch API (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to make HTTP calls. It has built-in support with Promise.
fetch('http://localhost:3000/listbuckets').then(response => {
// do something with the response here
}).catch(error => {
// Error :(
})
I eventually got this working with;
const request = require('request');
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
parseString(body, function (err, result) {
console.log(JSON.stringify(result));
});
// from within the callback, write data to response, essentially returning it.
res.send(body);
}
else {
// console.log(JSON.stringify(response));
}
})

Sails.js and Mocha: Using supertest to create a new model

I'm currently setting up testing infrastructure for my Sails app, and it was going smoothly until I tried testing API requests with supertest.
I'm trying to test some of my controller methods (that I implemented instead of using the default blueprint routes), but it seems like the API request isn't even going through. The reason I think this is because I can run npm test and this code will run fine, but if I change the POST path to /datamodel/create5, where create5() does NOT exist as a controller method, it still runs fine... In both cases, a DataModel model is NOT created. I've included some code below.
This is what my code looks like:
var request = require('supertest');
var assert = require('assert');
var async = require('async');
var stubs = require('../stubs.js');
describe('DataModel', function() {
var testDataModel;
var dataModelParams = stubs.dataModelStub(); // simply returns a JSON dictionary
describe('#create()', function() {
describe('data model import', function() {
it('should import a new data model.', function (done) {
var agent = request.agent(sails.hooks.http.app);
agent
.post('/datamodel/create')
.send(dataModelParams)
.expect(302)
.end(function (err, res) {
if (err) {
throw new Error(err);
}
console.log(res.dataModel);
DataModel.find().exec(function (err, dataModels) {
console.log(dataModels); // should return an array of 1 model but returns empty array instead
done();
});
});
});
});
});
Snippet of my controller code:
create: function(req, res) {
DataModel.create(req.params.all(), function dataModelCreated(err, dataModel) {
if (err) {
sails.log.debug(err);
}
FlashService.success(req, 'Successfully imported a new data model.');
fs.ensureDirSync(path.join(sails.config.paths.DATASET_EXTRACT_PATH, dataModel.fileSafeName));
fs.ensureDirSync(path.join(sails.config.paths.DATASET_DOWNLOAD_ROOT, 'non_pii', dataModel.fileSafeName));
fs.ensureDirSync(path.join(sails.config.paths.DATASET_DOWNLOAD_ROOT, 'pii', dataModel.fileSafeName));
fs.ensureDirSync(path.join(sails.config.paths.DATASET_ENCRYPT_PATH, dataModel.fileSafeName));
return res.redirect('/admin/manage_data_models');
});
}
Note that the create function runs correctly in practice when my app is launched. Any suggestions as to why my test isn't working properly? I'm using sails-memory for the tests if that helps.
I figured it out. I needed to authenticate my agent first (by making a call to the login route) before any of these calls would make it through.
Essentially:
var agent = request.agent(sails.hooks.http.app);
agent.post('YOUR_LOGIN_ROUTE').end(done);
// do your tests
Hmm, don't you need to pass something that looks like the sails app to supertest? There's an example here that shows what you need to do. Look at the before function in the second answer:
How to test controller using mocha in Sails?

Resources