Protractor: Using result of an api call - javascript

I created a small api to generate test data on the fly. Each call creates a fresh user and returns the created data.
To load the data I use the package request:
var flow = protractor.promise.controlFlow();
var result = flow.execute(function() {
var defer = protractor.promise.defer();
request('http://localhost/test/recipe/person', function (error, response, body) {
if (!error && response.statusCode === 200) {
defer.fulfill(JSON.parse(body));
}
});
return defer.promise;
});
To make any use of the retrieved data I have to resolve the promise and proceed the test script inside a callback:
result.then(function(data) {
element(by.model('username')).sendKeys(data.person.email);
element(by.model('password')).sendKeys('test');
$('button[type="submit"]').click();
});
I don't like this callback handling and the possible hell it will lead to. Besides that, Protractor is so good in hiding this messy callback handling thingy. So, the question is:
How to use the result of an async call?
At the end I would like to perform code like the following:
var flow = protractor.promise.controlFlow();
var result = flow.execute(function() {...});
element(by.model('username')).sendKeys(result.person.email);
//...
Any ideas?

You can either make the http request synchronous - In most cases that's a bad thing to do.
Or, you can insert the callback into the execute function:
var flow = protractor.promise.controlFlow();
var result = flow.execute(function() {
var defer = protractor.promise.defer();
request('http://localhost/test/recipe/person', function (error, response, body) {
if (!error && response.statusCode === 200) {
defer.fulfill(JSON.parse(body));
}
});
defer.promise.then(function(data) {
element(by.model('username')).sendKeys(data.person.email);
element(by.model('password')).sendKeys('test');
$('button[type="submit"]').click();
});
return defer.promise;
});
but result will stay a promise.

It worked for me:
var request = require('request');
var options = {
method: 'POST',
url: 'http://testurl.com/endpoint/test/',
headers: {'id': 'ABCD',
'sessionid': 'dummyId',
'Accept': 'application/json',
'Accept-Language': 'en-us'
},
body: '{ "pay_load": [] }'
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
console.log(body);
console.log(info);
}
}
request(options, callback);

Related

SyntaxError: Unexpected token e in JSON at position 1 with JSON.parse()

I am trying to use openweathermap.org weather api, I am getting the data but having trouble parsing it.
Here's my code:
request("https://api.openweathermap.org/data/2.5/weather?lat=30.4831&lon=76.595&appid=7beb6de85d3f3a28dabda1015684562f&units=metric&callback=test", function(error, response, body) {
if (!error && response.statusCode == 200) {
var parsedData = JSON.parse(body);
console.log(typeof body);
}
});
console.log(typeof body); returns string so I just can't figure out what 's the problem.
You are looking for this - the URL is JSONP so it expects a function called test and no need to parse
<script>
const test = data => console.log(data);
</script>
<script src="https://api.openweathermap.org/data/2.5/weather?lat=30.4831&lon=76.595&appid=7beb6de85d3f3a28dabda1015684562f&units=metric&callback=test"></script>
Alternatively remove the callback - here using fetch:
fetch("https://api.openweathermap.org/data/2.5/weather?lat=30.4831&lon=76.595&appid=7beb6de85d3f3a28dabda1015684562f&units=metric")
.then(response => response.json())
.then(data => console.log(data));
Or Axios
axios.get('https://api.openweathermap.org/data/2.5/weather?lat=30.4831&lon=76.595&appid=7beb6de85d3f3a28dabda1015684562f&units=metric')
.then(response => console.log(response.data));
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
This worked for me. Just set object for the first argument with url and json property. set json:true. Setting to true will handle the parsing for you :)
const request = require('request');
const url = "https://api.openweathermap.org/data/2.5/weather?lat=30.4831&lon=76.595&appid=7beb6de85d3f3a28dabda1015684562f&units=metric";
request({ url: url, json: true }, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
});
As #mplungjan pointed out. That's a JSONP url.
Remove &callback=test at the end of your URL then you don't have to deal with JSONP and you can work with it like normal.
Since you are using an API which has a callback function return as response. It is not JSON but JSONP (JSON with Padding).
Your code will work just fine if you remove the callback parameter from URL.
request("https://api.openweathermap.org/data/2.5/weather?lat=30.4831&lon=76.595&appid=7beb6de85d3f3a28dabda1015684562f&units=metric", function(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(response);
}
});
For further reading about JSONP, You can refer this.

How to pass query strings as arguments inside the HTTP request using 'request' library

I'm trying to develop a currency converter using node.js. I'm using 'request' to make HTTP requests.
Currently in my code, the query strings (q=1, from=USD, to=LKR) are hard coded in the url.
I want to know how to pass those strings as arguments in order to make it dynamic and get as many currency formats as I want.
var request = require('request');
const options = {
url : "https://currency-exchange.p.rapidapi.com/exchange?q=1&from=USD&to=GBP",
headers: {
'x-rapidapi-host': 'currency-exchange.p.rapidapi.com',
'x-rapidapi-key': 'b13c4f3d67msh8143a7f1298de7bp1e8586jsn4453f885a4e7'
}
}
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
console.log(response.body);
}
}
request(options, callback);
You can use the qs parameter in the request library when performing a new request.
As specified here https://stackoverflow.com/a/16903926/7088387
You could use this:
const params = {
q: 1,
from: 'USD',
to: 'GBP'
};
const options = {
url : "https://currency-exchange.p.rapidapi.com/exchange",
headers: {
'x-rapidapi-host': 'currency-exchange.p.rapidapi.com',
'x-rapidapi-key': 'b13c4f3d67msh8143a7f1298de7bp1e8586jsn4453f885a4e7'
},
qs: params
}
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
console.log(response.body);
}
}
request(options, callback);
You could have a variable that stores those:
var currencies = ['USD', 'GBP'];
And then just put those variable values into your request string:
url : "https://currency-exchange.p.rapidapi.com/exchange?q=1&from=" + currencies[0] + "&to=" + currencies[1]
You could also use template literals using backticks like so:
url : `https://currency-exchange.p.rapidapi.com/exchange?q=1&from=${currencies[0]}&to=${currencies[1]}`

How to handle multi-page requests to Github API with Node.js Request module?

I'm trying to access all repositories that have more than 5000 stars on Github. I've written this scraper to work with Node.js (it's running on a Cloud9 environment):
var request = require('request');
var fs = require('fs');
var options = {
url: 'https://api.github.com/repositories',
headers: {
'User-Agent': 'myusernamehere'
},
qs: {
stargazers: 5000
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(response.headers);
fs.writeFile('output_teste.json', body, function (err) {
if (err) throw err;
console.log('It\'s saved!');
console.log(response.statusCode);
});
} else {
console.log(response.statusCode);
}
}
request(options, callback);
But the result is not all of the repositories, just the first page of all of them. How can I use pagination with the Request module? I've tried to find examples within the documentation, but they aren't that clear. Or do I need to do this with another library or maybe another language?
Thanks!
you should modify your querystring to include the value of "since". You can read more on the github documentation.
https://developer.github.com/v3/repos/#list-all-public-repositories
Sample URL with query string of since
https://api.github.com/repositories?since=364
You could use the pagination data provided in response.headers.link that's received when making calls to the GitHub API to find out if there are any more pages left for your call.
One approach is to loop through the pages until there are no more new pages left, at which point you can write to file and return from function.
On each loop you can add to the data that you already have by using concat (I assume that the response body is delivered as an array) and then passing on the data to the next function call.
I rewrote your code to include a basic implementation of such a technique:
var request = require('request');
var fs = require('fs');
var requestOptions = function(page) {
var url = 'https://api.github.com/repositories?page=' + page;
return {
url: url,
headers: {
'User-Agent': 'myusernamehere'
},
qs: {
stargazers: 5000
}
};
};
function doRequest(page, incomingRepos) {
request(requestOptions(page), function(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(response.headers);
var currentPageRepos = JSON.parse(body);
var joinedRepos = incomingRepos.concat(currentPageRepos);
var linkData = response.headers.link;
// if response does not include reference to next page
// then we have reached the last page and can save content and return
if (!(linkData.includes('rel="next"'))) {
fs.writeFile('output_teste.json', JSON.stringify(joinedRepos), function(err) {
if (err) throw err;
console.log('It\'s saved!');
});
return;
}
page++;
doRequest(page, joinedRepos);
} else {
console.log(response.statusCode);
}
});
}
doRequest(1, []);

Google Cloud Functions - Nodejs error , forever loading

const request = require('request');
exports.helloWorld = function helloWorld(req, res) {
var headers = {
'scheme': 'https',
'authorization': 'Token 123',
'user-agent': 'mobile'
};
var options = {
url: 'https://url',
headers: headers
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
res.status(200).send(response.body);
}
}
request(options, callback);
};
I can submit a request without issue, but once i start doing a request with headers and options , i cant get it to work properly on Google Cloud Function.
Please advice on my mistake
Trigger type
: HTTP trigger
It's likely that an error is being returned from the call you're making using request, and since in the error case you don't end the function using res.end() or res.status(500).end(), Cloud Functions doesn't know if your function is done or not, so just runs it until a timeout is hit.
Try:
if (!error && response.statusCode == 200) {
console.log(body);
res.status(200).send(response.body);
} else {
console.log(error);
res.status(500).send(error);
}
You should get a response back without the Cloud Function hanging.

node.js request object- return response body for further operation [duplicate]

This question already has answers here:
How to return value from an asynchronous callback function? [duplicate]
(3 answers)
Closed 8 years ago.
There's probably an easy answer for this, but I'm trying to get the body of the response back and returned to another function. It's certainly a scope problem.
Here's my code, any ideas would be most appreciated:
var request = require("request");
var myJSON = require("JSON");
function getMyBody(url) {
var myBody;
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
myBody = body;
}
});
return(JSON.parse(myBody));
}
js_traverse(getMyBody(url));
Thanks
Glenn
The statement:
return(JSON.parse(myBody));
Get executed before the ajax call returns you the body. You need to pass in the callback to getMyBody() to do something with what the body of request() returns:
var request = require("request");
var myJSON = require("JSON");
function getMyBody(url, callback) {
request({
url: url,
json: true
}, function (error, response, body) {
if (error || response.statusCode !== 200) {
return callback(error || {statusCode: response.statusCode});
}
callback(null, JSON.parse(body));
});
}
getMyBody(url, function(err, body) {
if (err) {
console.log(err);
} else {
js_traverse(body);
}
});

Categories