I need some help here:
When I use debugger, everything works, but when debugger is not used, it not working.
When getAjax function is not called to get data from local server, then it the program is working and it can send mail
function sendMessage(headers_obj, message, callback) {
var pGmail = $('#compose-to').val();
getAjax(pGmail).then(result => {
var email = '';
message = encryptText(result, message);
for (var header in headers_obj) {
email += header += ": " + headers_obj[header] + "\r\n";
}
email += "\r\n" + message;
alert(email);
if(email!=null|| email!=''){
var mail = encodeBase64(email);
var sendRequest = gapi.client.gmail.users.messages.send({
'userId': 'me',
'resource': {
'raw': mail
}
})
sendRequest.execute(callback)
}
})
}
function getAjax(pGmail) {
return new Promise((resolve) => {
$.ajax({
url: 'http://localhost:7777/' +
'?pmail=' + pGmail + '&method=where', success: function (result) {
return resolve(result);
}
})
});
}
Trick lies in the time delay.
When I use debugger, everything works, but when debugger is not used, it not working
When you are in Debug mode, the getAjax call is able to complete its request and the response is arrived. Since while debugging there is a small time delay for us to step over to next line of code.
When getAjax function is not called to get data from local server, then it the program is working and it can send mail
Obviously there is no need to of time delay here, since you are not calling getAjax function.
Few Solution Approaches
Option 1 : Make it synchronous
Even though the getAjax is an asynchronous call, we can wire up the email sending code in the response of getAjax call, thus making it synchronous,
Option 2 : Introduce a time delay between getAjax and email sending code.
Please note in this approach, the time delay which might be higher or lower than the time taken by getAjax function and in some cases it may fail, if the getAjax call doesn't respond within in the time delay.
Choose the option which suits best for your scenario.
Hope it helps!
var mysql = require('mysql');
var http = require("http");
var url = require("url");
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "1234",
database: 'publickeyserver'
});
con.connect(function (err) {
if (err) throw err;
console.log("Connected!");
});
http.createServer(function (req, res) {
var query = url.parse(req.url, true).query;
switch (query.method) {
case "insert":
var pkey = new Buffer(query.publickey,
'base64').toString('ascii');
insertKey(query.pmail, pkey, res);
break;
case "where":
getKey(query.pmail, res);
break;
default:
console.log("Error");
}
}).listen(7777);
function insertKey(pmail, publickey, res) {
var value = [[pmail, publickey]];
var sql = "INSERT INTO publickey (GmailId, PublicKey) VALUES ?";
con.query(sql, [value], function (err, result) {
if (err) throw err;
console.log("success");
res.write('success');
res.end();
});
}
function getKey(pmail, res) {
console.log(pmail);
var sql = 'SELECT PublicKey FROM publickey WHERE GmailId = ?';
con.query(sql, [pmail], function (err, result) {
if (err) throw err;
res.writeHead(200, { "Content-Type": "text/plain" });
res.end(result[0]['PublicKey']);
console.log(result[0]['PublicKey']);
});
}
Here is my server code, i use nodejs
Related
I want to create a uptime monitor using NodeJS and MongoDB. I want to run a cron job in NodeJS and store the data into MongoDB. If the website response status code is not equal to 200 then it will be saved in the database. I want to make a database entry like this,
url : http://www.google.com
status_code : 500
start_time :- start time
end_time :- end time
I can run the cron job but not sure how to save the downtime in the database. As, I don't want to store every response into the database. Only when response status code is other than 200 , then it will start tracking (start_time) the URL and it keeps the time when website is back to 200 as end_time.
cron.js :-
var async=require('async');
const Entry = require('../models/health.model.js');
var https = require('https');
var request = require('request');
module.exports = function getHttpsRequests () {
Entry.find({},function(err,entrys){
console.log(err);
if(!err && entrys){
async.each(entrys,function(entry,callback){
request(entry.url, function (error, response, body) {
entry.statuscheck=response.statusCode;
entry.save();
callback();
});
},function (error) {
});
}
});
}
health.model.js :-
const mongoose = require('mongoose');
const EntrySchema = mongoose.Schema({
url: String,
statuscheck: String
}, {
timestamps: true
});
module.exports = mongoose.model('Entry', EntrySchema);
I would do something like this to handle updating the database. I went ahead and put standard arrow functions in, because it was easier for me that way. I put some comments in so that should clear most questions up. It may not be the most elegant solution because I wrote it in 5 minutes, but if you follow this general logic flow, you should be much closer to your solution (its completely untested mind you.)
var async=require('async');
const Entry = require('../models/health.model.js');
var https = require('https');
var request = require('request');
module.exports = function getHttpsRequests () {
Entry.find({}, (err,entrys) => {
console.log(err);
if (!err && entrys) {
async.each(entrys, (entry,callback) => {
request(entry.url, (error, response, body) => {
//first check if the url has a document in the db.
Entry.find({ url: entry.url }, (err, entry) => {
if(!entry) {
//since the document does not exist, check the statusCode.
if(response.statusCode===200) { //if the statusCode is 200, continue the loop.
callback();
} else { //if the status code is not 200, lets save this to the db.
console.log("Saving object: " + entry)
entry.status_code = response.statusCode;
entry.start_time = new Date();
entry.save();
callback();
}
} else if (entry) {
//since the document exists, lets check the statusCode.
if(response.statusCode===200) { //if the statusCode is 200, update the stop_time.
entry.end_time = new Date();
Entry.findOneAndUpdate({ url: entry.url }, entry, (err, object) => { //this returns the entry after update, so we can put that in the console for easy debug.
if (err) {
console.log(err);
callback();
} else {
console.log("Object saved: " + object);
callback();
}
});
}
} else { //there was an error finding the document in the db, just go to the next one.
callback();
});
});
});
}
});
}
I have been struggling with the returning of data for the past 2 days. I really need help in getting the data to show in another .js file but I can't seem to do so.
From all the research I have done, I know that I need the callback function in order to do the return. When I output the data in file1.js, it shows, which is correct.
However, I need to access the returned data in my file2.js but it is not showing.
Am I missing anything out? Please help, any response is greatly appreciated. Thanks.
Note that my return statement in file1.js is near the end of the code.
Also, my "res" array is ALWAYS empty when accessed outside the function. Why is this so?
file1.js
var sql = require("mssql");
// Create a configuration object for our Azure SQL connection parameters
var dbConfig = {
server: "***", // Use your SQL server name
database: "***", // Database to connect to
user: "***", // Use your username
password: "***", // Use your password
port: 1433,
// Since we're on Windows Azure, we need to set the following options
options: {
encrypt: true
}
};
var obj = {};
var res = [];
// This function connects to a SQL server, executes a SELECT statement,
// and displays the results in the console.
function getProducts(callback) {
// Create connection instance
var conn = new sql.ConnectionPool(dbConfig);
conn.connect()
// Successfull connection
.then(function () {
// Create request instance, passing in connection instance
var req = new sql.Request(conn);
// Call mssql's query method passing in params
req.query("SELECT sp.product_name, count(ss.product_id) as 'quantity' " +
"FROM smartcoolerstocks ss JOIN smartcoolerproducts sp " +
"ON sp.product_id = ss.product_id " +
"GROUP by sp.product_name ")
.then(function (recordset) {
//console.log(recordset.recordset);
conn.close();
//NEED CALLBACK FUNCTION
console.log(recordset.recordset.length);
for(var i = 0; i<recordset.recordset.length; i++ ){
res.push(recordset.recordset[i]);
}
callback(null,recordset.recordset);
process.exit(1);
})
// Handle sql statement execution errors
.catch(function (err) {
console.log(err);
conn.close();
})
})
// Handle connection errors
.catch(function (err) {
console.log(err);
conn.close();
});
}
//call Fn for db query with callback
getProducts(function(err,data){
if (err) {
// error handling code goes here
console.log("ERROR : ",err);
} else {
// code to execute on data retrieval
//console.log("result from db is : ",data.recordset);
//return data.recordset;
return res;
}
});
console.log(res); //WHY IS THIS EMPTY HERE?
module.exports = {
getProducts(){},
};
Blockquote
file2.js
var myDB2 = require('./sqltest2');
console.log(myDB2.getProducts());
Here's my output in cmd:
After the '7', there's nothing showing.
My IDEAL output should be the following if I manage to get the returned data in file2.js from file1.js:
You cannot see the res because its race condition, your console.log(res) executed earlier than recordset callback.
file1.js already executed the getProducts function so there is not data that returned to file2.js.
var sql = require("mssql");
// Create a configuration object for our Azure SQL connection parameters
var dbConfig = {
server: "***", // Use your SQL server name
database: "***", // Database to connect to
user: "***", // Use your username
password: "***", // Use your password
port: 1433,
// Since we're on Windows Azure, we need to set the following options
options: {
encrypt: true
}
};
var obj = {};
var res = [];
// This function connects to a SQL server, executes a SELECT statement,
// and displays the results in the console.
function getProducts(callback) {
// Create connection instance
var conn = new sql.ConnectionPool(dbConfig);
conn.connect()
// Successfull connection
.then(function() {
// Create request instance, passing in connection instance
var req = new sql.Request(conn);
// Call mssql's query method passing in params
req.query("SELECT sp.product_name, count(ss.product_id) as 'quantity' " +
"FROM smartcoolerstocks ss JOIN smartcoolerproducts sp " +
"ON sp.product_id = ss.product_id " +
"GROUP by sp.product_name ")
.then(function(recordset) {
conn.close();
callback(null, recordset.recordset);
process.exit(1);
})
// Handle sql statement execution errors
.catch(function(err) {
console.log(err);
conn.close();
callback(err, null);
})
}).catch(function(err) {
console.log(err);
conn.close();
callback(err, null);
});
}
module.exports = getProducts;
And file2.js
var myDB2 = require('./sqltest2');
myDB2(function(err, data){
if( err ) console.log(err);
else console.log(data);
});
So a simple explanation of what I am doing. First, I am accepting a GET request from an end user. Second, I am passing a (I am making a GET request now) parameter from the get request to an async function that returns a user's email address based on the parameter (essentially a vanity url. "Bob" vs "Robert Richardson").
Third, I am making on more GET request, to a second system, which returns a JSON file containing different tidbits about the user.
I know the callouts work normally because I can run node index.js with a function where I manually pass in the information I need, and it returns the desired results. But when I start my nodejs server, and try to respond to an incoming GET request (me testing, definitely not live) I get very weird results...
Here is simply what I am trying to get working at the moment:
//server.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 8000;
app.use(bodyParser.urlencoded({
extended: true
}));
require('./app/routes')(app, {});
app.listen(port, () => {
console.log('test is listening on port :: ' + port);
});
//routes.js
const getdata = require('./getData '); //contains function for GET request one to convert param to email
async function getReturn(app, db) {
app.get('/getDataFrom/:alias', (req, res) => {
const alias = req.params.alias;
console.log('alias : ' + alias);
getEmailFromPromise(alias);
});
}
async function getEmailFromPromise(alias) {
console.log('getting email');
let output = await getEmail(alias);
console.log('output :: ' + output);
// return output;
}
function getEmail() {
return new Promise(resolve => {
let email = getdata.getUserInfo(alias);
resolve(email);
}, 1000);
}
Worth noting, JS and Node are not what I commonly code it, but I need to for a project I am helping out with. I can get simple examples to work, but not my one making requests.
Passing in GET: localhost:8000/getDataFrom/bob
The above returns the following:
test is listening on port :: 8000
alias : rrichardson
getting email
output :: undefined //I am wanting this to log after I actually get the email
email found :: robert.richardson#company.com //I do get this back, but out of order. The undefined above should also be this
The other file if it helps (it is exported properly):
//this is callout one getData
async function getUserInfo(alias){
client.connect();
client.query('select email, firstname, lastname from salesforce.user WHERE
alias = \''+ alias + '\'', (err, res) => {
if (err) console.log('err :: ' + err);
// console.log(res.rows);
client.end();
var email = res.rows[0].email;
if(email != null){
console.log('email found :: ' + email);
return email;
}
else return 'No Email Found';
});
}
Obviously I left out my credentials, but the last js file DOES work just fine when I pass specific data into it. Again, just issues when trying to respond to a GET request that is incoming to me. I would really appreciate any help clearing this up. I am pretty sure I can get the second GET request figured out if I can get some help figuring out this first one.
Thanks!
You need getReturn to return the promise generated by the getEmailFromPromise call. Because app.get uses a callback rather than a promise, you'll have to explicitly convert it to a promise first - in which case there's not much use in making getReturn async.
function getReturn(app, db) {
return new Promise((resolve) => {
app.get('/getDataFrom/:alias', (req, res) => {
const alias = req.params.alias;
console.log('alias : ' + alias);
getEmailFromPromise(alias)
.then(resolve);
});
});
}
The other problem is that getUserInfo also uses callbacks rather than promises - you can't just turn it into an async function, you'll have to explicitly convert it to return a Promise as well:
function getUserInfo(alias){
return new Promise((resolve, reject) => {
client.connect();
client.query('select email, firstname, lastname from salesforce.user WHERE
alias = \''+ alias + '\'', (err, res) => {
if (err) {
console.log('err :: ' + err);
reject(err);
}
// console.log(res.rows);
client.end();
var email = res.rows[0].email;
if(email != null){
console.log('email found :: ' + email);
resolve(email);
}
else resolve('No Email Found');
});
});
}
You also need to use await to consume promises if you want the line below to run only after the promise has resolved:
function getEmail() {
return new Promise(resolve => {
let email = await getdata.getUserInfo(alias);
But it doesn't make much sense to await something that's a promise if you're just going to resolve it immediately. (and the second argument you provide to the promise in getEmail, 1000, doesn't make any sense)
Just return the promise itself:
function getEmail() {
return getdata.getUserInfo(alias);
}
you are mixing async and promises, it would be avoid.
Your problem is th function getUserInfo is async but it has no "await" part, it is not waiting for "resolve" or return so it returns nothing or "undefined" because you ra anssigning that to the email in " let email = getdata.getUserInfo(alias);" you could use primse in this step, some like this:
function getUserInfo(alias){
return new Promise(function(resolve, reject){
client.connect();
client.query('select email, firstname, lastname from salesforce.user WHERE alias = \''+
alias + '\'', (err, res) => {
if (err) reject('err :: ' + err);
// console.log(res.rows);
client.end();
var email = res.rows[0].email;
if(email != null){
console.log('email found :: ' + email);
resolve(email);
}
else reject('No Email Found');
});
}
}
and call it:
function getEmail() {
return new Promise(resolve => {
getdata.getUserInfo(alias).then(function(email){
resolve(email);
});
});
}
I am attempting to send a text message when a user requests to reset their password. I would like to wait for the message to be sent to alert the user if it was successful or not. I am currently attempting to do it as follows:
async function sendResetPasswordTextMessage(req, res) {
let result = {};
let phoneNumber = req.body.phoneNumber;
if (phoneNumber === undefined) {
return sendInvalidParametersMessage(res);
}
phoneNumber = phoneNumber.toString();
const userProfile = await models.UserProfile.findOne({
where: {
phoneNumber: phoneNumber
}
});
************************** RELEVANT CODE TO ISSUE *************************
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
const sent = await AWSSNSClient.sendMessage(message, phoneNumber);
if (!sent) {
result.error = setTitleAndMessage("Error", "An error occurred");
} else {
result.success = setTitleAndMessage("Success", "Message sent");
}
}
return res.send(result);
***************************************************************************
}
In my other class AWSSNSClient, I have the following sendMessage function:
function sendMessage(message, phoneNumber) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
let sent = false;
sns.publish(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
sent = true;
}
});
return sent;
}
I cannot figure out how to make sendMessage wait for sns.publish to return before it returns itself. I have tried making it an async method and adding await on sns.publish, but the function still returns before sent gets set to true.
I know that the messages are sending without error because I am receiving them and no console logs are printed.
Stumbled on this one via Google trying to figure this out myself today - short answer that I am now using:
You can now do this with Async/Await — and Call the AWS service (SNS for example) with a .promise() extension to tell aws-sdk to use the promise-ified version of that service function (SNS) instead of the call back based version.
The only caveat here is the containing function must ALSO be async to utilize the await syntax.
For example:
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("SNS Push Failed:");
console.log(err.stack);
return;
}
console.log('SNS push suceeded: ' + data);
return data;
}).promise();
The important part is the .promise() on the end there. Full docs on using aws-sdk in an async / promise based manner can be found here: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html
In order to run another aws-sdk task you would similarly add await and the .promise() extension to that function (assuming that is available).
For anyone who runs into this thread and is actually looking to simply push multiple aws-sdk promises to an array and wait for that WHOLE array to finish (without regard to which promise executes first) I ended up with something like this:
let snsPromises = [] // declare array to hold promises
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return;
}
console.log('Search push suceeded: ' + data);
return data;
}).promise();
snsPromises.push(snsResult)
await Promise.all(snsPromises)
Hope that helps someone that randomly stumbles on this via google like I did!
stackdave will that actually wait?
Necevil "Search push suceeded will get logged twice" because you're mixing calling operations by passing a callback and using promises. You should only use one method of getting the result
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn}).promise()
will do the trick
You can simply use callbacks for that. Modify your sendMessge like this
function sendMessage(message, phoneNumber, cb) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
sns.publish(params, cb);
}
then on your main file you can supply callback like this
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
AWSSNSClient.sendMessage(message, phoneNumber, (err, data) => {
if (err) {
result.error = setTitleAndMessage("Error", "An error occurred");
}
else {
result.success = setTitleAndMessage("Success", "Message sent");
}
res.send(result);
});
}
Here the right updated API, August 2018, Necevil answer send the sms twice.
// using config.env
AWS.config.region = 'eu-west-1';
AWS.config.update({
accessKeyId: process.env.AMAZON_SMS_ID,
secretAccessKey: process.env.AMAZON_SMS_TOKEN,
});
// parameters
let params = {
Message: contentSMS, // here your sms
PhoneNumber: mobile, // here the cellphone
};
const snsResult = await sns.publish(params, async (err, data) => {
if (err) {
console.log("ERROR", err.stack);
}
console.log('SNS ok: ' , JSON.stringify (data));
});
If you're having issues with duplicate SNS messages being sent, I fixed this issue by utilizing examples from AWS:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'REGION'});
// Create publish parameters
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: 'TOPIC_ARN'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
publishTextPromise.then(
function(data) {
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
By utilizing a traditional .then() I was able to squash the duplicate message bug mentioned in comments above.
You can create a async function what use the promise method
async function sendMessage(message, phoneNumber){
const params = {
Message: message,
PhoneNumber: phoneNumber
};
return new Promise((resolve, reject) => {
SNS.publish(params, (err, data) => {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return reject(err);
} else {
console.log('Search push suceeded:' + phoneNumber);
return resolve(data);
}
})
});
}
and then you can call
var s= await sendMessage(message,phoneNumber);
I want to make a HTTPS request to an external link through Node JS. On my first call, I need to fetch user id by looping through several users. On my second call, I need to input that user id in the URL link and fetch user properties. Keep repeating this process till I go through all users. The end goal is to store data of every user in a JSON format. There is no front-end involved. Any direction/advice is much appreciated.
I can't share the actual link due to api keys. But here is the hypothetical scenario. I only show 2 users here. I have about 10,000 users in my actual data set.
Link 1
https://www.google.com/all_users
JSON Output
{
"name": "joe",
"uri": "/id/UserObject/User/1234-1234",
},
{
"name": "matt",
"uri": "/id/UserObject/User/5678-5678",
}
Link 2
https://www.google.com//id/UserObject/User/1234-1234
JSON Output
{
"name": "joe",
"uri": "/id/UserObject/User/1234-1234",
"Property Values": {
"height": "2",
"location": "canada"
},
"Other Values": {
"work": "google",
"occupation": "developer"
}
}
Nested JSON
{
"PropertySetClassChildrenResponse": {
"PropertySetClassChildren": {
"PropertySetInstances": {
"totalCount": "1",
"Elements": [
{
"name": "SystemObject",
"uri": "/type/PropertySetClasses/SystemObject"
}
]
}
}
}
}
Not tested, but this should point you in the right direction. It uses Promises and assumes that run in an ES6 environment:
const rp = require('request-promise');
const Promise = require('bluebird');
fetchAllUsers()
.then(extractUserUris)
.then(extractUserIds)
.then(buildUserDetailRequests)
.then(Promise.all) // run all the user detail requests in parallel
.then(allUserData => {
// allUserData is an array of all users' data
});
function fetchAllUsers() {
return rp('https://api.whatever.com/all_users');
}
function extractUserUris(users) {
return users.map(user => user.uri);
}
function extractUserIds(userUris) {
return userUris.map(userUri => userUri.split('/').pop());
}
function buildUserDetailRequests(userIds) {
return userIds.map(userId => rp("https://api.whatever.com/user/" + userId));
}
I'd suggest using the request package to make your HTTP requests easier.
> npm install request
Then you would obtain a list of all users with something like this:
var request = require('request');
request.get({url: "https://example.org/all_users"}, handleUsersResponse);
You'd handle the request response like this:
function(err, response, body) {
if (!err && response.statusCode == 200) {
// parse json (assuming array of users)
var users = JSON.parse(body);
// iterate through each user and obtain user info
for(var i = 0; i < users.length; i++) {
var userUri = users[i].uri;
obtainUserInfo(userUri)
}
}
}
obtainUserInfo function would be similar to the above code.
One important thing to keep in mind is that since the HTTP requests are being made asynchronously, when you make the requests in a loop, the next iteration of the loop does not wait until the work is finished before moving to the next iteration and starting the next request. So in effect, your loop would start all the HTTP requests nearly in parallel. This can easily overwhelm both your client and the server. One way to get around this is to use a worker queue to enqueue the work and ensure that only a maximum number of HTTP requests are being executed at any given time.
You don't want to do synchronous calls, it defeats the purpose of using Node. So by the Node powers invested in me by the State of Texas I hereby cast that synchronous way I thinking out of you!
Just kidding :), but let's do this the Node way.
Install these two libraries:
sudo npm install Promise
sudo npm install request
And set your code to look like:
var Promise = require('promise');
var request = require('request');
//Get your user data, and print the data in JSON:
getUserData()
.then(function(userData) {
console.log(JSON.stringify(userData));
}).catch(function(err) {
console.log('Error: ' +err);
});
/**
* Prepares an Object containing data for all users.
* #return Promise - Contains object with all user data.
*/
function getUserData() {
return new Promise(function(fulfill, reject) {
// Make the first request to get the user IDs:
var url1 = 'https://www.google.com/all_users';
get(url1)
.then(function(res) {
res = JSON.parse(res);
// Loop through the object to get what you need:
// Set a counter though so we know once we are done.
var counter = 0;
for (x=0; x<res.users.length; x++) {
var url2 = 'https://www.google.com//id/UserObject/User/';
url2 = url2 + res.users.id; //Wherever the individual ID is stored.
var returnDataArr = [];
get(url2)
.then(function(res2) {
// Get what you need from the response from the 2nd URL.
returnDataArr.push(res2);
counter++;
if (counter === res.users.length) {
fulfill({data: returnDataArr}); //Return/Fulfill an object containing an array of the user data.
}
}).catch(function(err) {
// Catch any errors from the 2nd HTTPS request:
reject('Error: ' +err);
});
}).catch(function(err) {
// Catch any errors from the 1st HTTPS request:
reject('Error: ' +err);
});
}
/**
* Your HTTPS GET Request Function
* #param url - The url to GET
* #return Promise - Promise containing the JSON response.
*/
function get(url) {
return new Promise(function(fulfill, reject) {
var options = {
url: url,
headers: {
'Header Name': 'Header Value',
'Accept': 'application/json',
'Content-Type': 'application/json'
};
request(options, function(err, res, body) {
if (err) {
reject(err);
} else {
fulfill(body);
}
});
});
}
So what this Promise does, is that it returns the value once we actually have it. In the code above, we are first getting that list of users, and then as we parse through it, we are making a new asynchronous HTTP request to get the additional data on it. Once we get the user data, we push it to an array.
Finally, once our counter hits its endpoint, we know that we have gotten all the user data, and so we call fulfill which essentially means return, and it returns an object containing an array of the user data.
Let me know if this makes sense.
The answers above helped me go further with my solution and get the desired outcome. However, I spent a lot of time trying to understand node, promises in node, making an API call, etc. Hopefully, this will help to a beginner level node developer.
NODE
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
If you are a JavaScript developer, you would prefer to use Node as you wouldn't have to spend time learning a new language like Java or Python.
GOAL
Make a HTTPS call to an external link to fetch all server URIs. Pass in the URI as a param to create a second link to fetch all server properties. Loop through to all server uris and properties. Refer the original post on the top for the data structure. The external link also required basic auth and headers.
CODE
Install NPM modules request (https call), bluebird (promises) and lodash(utility) and express(node framework).
/
********************** MODULES/DEPENDENCIES **********************/
var express = require('express');
var request = require('request');
var Promise = require('bluebird');
var _ = require("lodash");
/********************** INITIATE APP **********************/
var app = express();
console.log("Starting node server...");
/**
* Your HTTPS GET Request Function
* #param url - The url to GET
* #return Promise - Promise containing the JSON response.
*/
function get(url) {
return new Promise(function(resolve, reject) {
// var auth = "Basic " + new Buffer(username + ':' + password).toString("base64");
var options = {
url: url,
headers: {
// 'Authorization': auth,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
};
console.log("Calling GET: ", url);
if ('development' == app.get('env')) {
console.log("Rejecting node tls");
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}
request(options, function(error, response, body) {
if (error) {
reject(error);
} else {
// console.log("THIS IS BODY: ", body);
resolve(body);
}
});
});
}
/********************** GET DATA FUNCTION **********************/
function getServerData() {
/********************** URI VARIABLES **********************/
var username = 'username',
password = 'password',
role = 'Read-Only',
url_host = 'https://link.com:10843';
/********************** URL 1 **********************/
var url1 = url_host + '/type/PropertySetClasses/SystemObject/Server/?maxResults=1000&username=' + username + '&password=' + password + '&role=' + role;
console.log("Getting server data...", url1);
/********************** GET REQUEST 1 **********************/
return get(url1)
.then(function(res) {
console.log("Got response!");
res = JSON.parse(res);
res = res.PropertySetClassChildrenResponse.PropertySetClassChildren.PropertySetInstances.Elements;
// console.log("THIS IS RES: ", res);
/********************** FETCH URI FROM RES NESTED OBJECT **********************/
var server_ids = _.map(res, function(server) {
return server.uri;
});
console.log("Calling server urls", server_ids);
// Loop through the object to get what you need:
// Set a counter though so we know once we are done.
return Promise.map(server_ids, function (id) {
var url2 = url_host + id + '?username=' + username + '&password=' + password + '&role=' + role;
console.log("Calling URL", url2);
return get(url2)
.then(function(res2) {
res2 = JSON.parse(res2);
var elements = res2.PropertySetInstanceResponse.PropertySetInstance.PropertyValues.Elements;
console.log("Got second response", res2, elements);
return elements;
});
})
.then(function (allUrls) {
console.log("Got all URLS", allUrls);
return allUrls;
});
})
.catch(function(err) {
console.error(err);
throw err;
});
};
app.listen(8080, function() {
console.log("Server listening and booted on: " + 8080);
app.get("/serverInfo", function (req, res) {
console.log("Calling server info");
return getServerData()
.then(function(userData) {
var userData = JSON.stringify(userData, null, "\t");
console.log("This is USERDATA Data: ", userData);
res.send(userData);
})
.catch(function(err) {
console.error(err);
res.send({
__error: err,
message: err.message
});
});
});
});