I am using this code to download files in node js :
var currentVideoRequest = null;
window.spawnVideoPlayer = function (url, subs, movieModel,tag) {
if(currentVideoRequest) {
try
{
currentVideoRequest.abort();
}
catch(err)
{
alert(err.message);
}
}
var fs = require('fs');
var urlrequest = currentVideoRequest = require('request');
urlrequest.get({url: url, encoding: 'binary'}, function (err, response, body) {
fs.writeFile(FILEURL, body, 'binary', function(err) {
});
});
}
And in the currentVideoRequest.abort(); i get this error:
Object function request(uri, options, callback) {
if (typeof uri === 'undefined') throw new Error('undefined is not a valid uri or options object.')
if ((typeof options === 'function') && !callback) callback = options
if (options && typeof options === 'object') {
options.uri = uri
} else if (typeof uri === 'string') {
options = {uri:uri}
} else {
options = uri
}
options = copy(options)
if (callback) options.callback = callback
var r = new Request(options)
return r
} has no method 'abort'
To add to #Etai's answer, you need to require the request module before using it for one instance of the request. Something like this:
var request = require('request');
// ...
// then later in the code
var urlrequest = request.get(uri, function(err, response, body) {
// process data here
});
// later, you'd abort this as:
urlrequest.abort();
Note that I'm saving the instance with var urlrequest = request.get(params, callback); so that I can call abort on it later.
your currentVideoRequest is a constructor for a request object, not a request object, which is why this is failing.
The request constructor returns a request object when invoked, i.e.
require('request')('uri', function(err, resp, body){})
you can use abort() method to stop that request.
var reqObj = request({uri: 'https://jsonplaceholder.typicode.com/albums' }, function (error, response, body) {
console.log('API requested ') ;
if (!err){
console.log(body);
}
else
{
console.log(err);
}
});
reqObj.abort();
I think you can use this method to get what you need.
I used async in this way, which makes both the code cleaner and less callback .
(async function main() {
try {
let urlRequest = await customRequest("http://127.0.0.1:8000/api/product/search?title=foo");
urlRequest.abort();
} catch (e) {
console.log(e);
}
})();
function customRequest(url) {
return new Promise((resolve, reject) => {
request.get(url, (err, res) => {
if (err) reject(err)
if (res.statusCode !== 200)
reject("my Error ");
resolve(res);
})
})
}
Also, if you do not need to answer the urlRequest variable,you can remove the await from the function as shown below.
try {
let urlRequest = customRequest("http://127.0.0.1:8000/api/product/search?title="); // run in background !
urlRequest.abort();
} catch (e) {
console.log(e);
}
Finally, since our request returns an exception if you make a mistake, you can write abort() in the catch block if needed.
(async function main() {
try {
var urlRequest =await customRequest("http://127.0.0.1:8000/api/product/search?title=");
} catch (e) {
urlRequest.abort();
console.log(e);
}
})();
Also, because the customRequest() function returns a promise note, you use then() instead of async await.
Related
I have the following code.
I'm trying to make an API call (retrieve) passing since (obj.since), therefore, every time I make the call the API does not retrieve all data. However, so far, I haven't found the way to get since from the last record on my database.
var express = require("express");
var article = require("../models/article");
var request = require('request');
article.findOne({}, {since:1, _id:0}, { sort: { 'since' : -1 } }, function (err,obj) {
var **dataString** = `'{"consumer_key":"XXXXX", "access_token":"XXXXXXX", "since":"${obj.since}"}'`;
});
var options = {
url: 'https://xxxxxxxxx.com/v3/get',
method: 'POST',
headers: headers,
body: **dataString**
}
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
let package = JSON.parse(body);
for(var attributename in package.list){
var title = package.list[attributename]["given_title"] ;
var url = package.list[attributename]["given_url"] ;
var newArticle = {title: title, url: url, since: since}
article.create(newArticle, function(error, newlyCreated){
if(error){
console.log(error);
} else {
console.log(newlyCreated);
}
});
}
}
else {
console.log(error);
}
};;
request(options,callback)
How can I make an API call getting the obj.since from the database (MongoDB) and pass it to an object (options)?
You are doing async callback style operation in for loop which is causing this issue. I will change few things
Change findOne to have exec at the end so it returns promise
article.create already returns a promise if no callback specified.
Convert request to a promise style.
Use for..of loop to do async operation.
The code will look like this
var express = require("express");
var article = require("../models/article");
var request = require('request');
function hitApi(dataString) {
return new Promise((resolve, reject) => {
var options = {
url: 'https://xxxxxxxxx.com/v3/get',
method: 'POST',
headers: headers,
body: dataString
}
request(options, error, response, body => {
if (err) {
reject(err);
}
resolve(body);
});
});
}
async function perform() {
const dataString = await article.findOne({}, {since:1, _id:0}, { sort: { 'since' : -1 } }).exec();
const response = await hitApi(dataString);
const package = JSON.parse(response.body);
for (const attributename of package.list) {
var title = package.list[attributename]["given_title"] ;
var url = package.list[attributename]["given_url"] ;
var newArticle = {title: title, url: url, since: since}
const newlyCreated = await article.create(newArticle);
console.log(newlyCreated);
}
}
You can then call perform function. There might be few syntax error but you will get an idea.
I've read a couple of posts about this here (callbacks) but I still don't really fully understand how to solve my problem. So I was hoping that somebody here could help me with mine and I would get it better.
Simple put I want the ID I get from the first request to be used for the second request.
I'm new to JavaScript and NodeJS in general.
function idRequest(name) {
var options = {
...
};
function callback(error, response, body) {
if (response.statusCode == 200 && !error) {
const info = JSON.parse(body);
//console.log(info.accountId);
return info.accountId;
}
}
request(options, callback);
}
function requestById(accountId) {
var options = {
...
};
function callback(error, response, body) {
if (response.statusCode == 200 && !error) {
const info = JSON.parse(body);
console.log(info);
}
}
request(options, callback);
}
var id = idRequest('..');
requestById(id);
Try by returning a promise from the first function and inside it resolve the callback, so the once it is resolved , you can use it's then to trigger the second function
function idRequest(name) {
var options = {
...
};
function callback(error, response, body) {
if (response.statusCode == 200 && !error) {
const info = JSON.parse(body);
//console.log(info.accountId);
return info.accountId;
}
}
return new Promise(function(resolve, reject) {
resolve(request(options, callback))
})
}
function requestById(accountId) {
var options = {
...
};
function callback(error, response, body) {
if (response.statusCode == 200 && !error) {
const info = JSON.parse(body);
console.log(info);
}
}
request(options, callback);
}
var id = idRequest('..').then(function(data) {
requestById(data);
});
since callback is a async call, so var id will be undefined, when you call the requestById(id);
so either you can use the promise method, answered by #brk or you can call your requestById(id) function directly from the first callback.
[EDIT] While trying to implement the promise I get the following error:
TypeError: Cannot read property "then" of undefined
getResult(options1).then(function(body){...
let options1 = {...};
app.post("/webhook", function (req, res) {
if (req.body.object_type === "activity" && req.body.aspect_type === "create"){
getResult(options1).then(function(body){
res.sendStatus(body.main.temp_max);
})
}
});
// listen for requests :)
var listener = app.listen(process.env.PORT, function () {
console.log('Your app is listening on port ' + listener.address().port);
})
function getRequest(options){
return new Promise(function(resolve, reject){
request(options, function (error, response, body) {
if (error) reject(new Error(error));
var body = JSON.parse(body);
resolve(body);
console.log(body)
})
})
}
function getResult(options){
getRequest(options).then(function(body){
// you have the body of the first response
let options2 = { ...};
// construct a options2 using this body
return getRequest(options2);
})
}
you can do it in the following way
function getRequest(options){
return new Promise(function(resolve, reject){
request(options, function (error, response, body) {
if (error) reject(new Error(error));
var body = JSON.parse(body);
resolve(body);
})
})
}
function getResult(options){
return getRequest(options)
.then(function(body){
// you have the body of the first response
let options2 = {};
// construct a options2 using this body
return getRequest(options2);
})
}
let options1 = {};
// initial options
getResult(options1).then(function(body){
res.sendStatus(body.main.temp_max);
})
I'm trying to convert my existing code using BlueBird, please suggest a best option to chain multiple request. Error happening in each callback needs to be redirected to rendered with different error.
request(option1, function (error, response, body) {
if (!error && response.statusCode == 200) {
var data= JSON.parse(body);
if(data.valid){
if(data.expired){
next();
} else {
request(option2, function (error2, response2, body2) {
var data2= JSON.parse(body2);
if(data2.valid) {
request(option3, function (error3, response3, body3) {
next();
})
} else {
res.json({error:'Error1'});
}
})
}
} else {
res.json({error:'Error2'});
}
} else {
res.json({error:'Error3'});
}
})
This is pretty straightforward, also note your current code doesn't handle errors in the second and third requests and this does:
var request = require("request-promise"); // request - converted to bluebird
request(option1).then(data=> {
if(!data.valid) throw Error("Error3");
if(data.expired) return;
return request(option2).then(JSON.parse);
}).then(data2 => {
if(!data2) return; // didn't need to fetch additional data
if(!data2.valid) throw Error("Error2");
return request(option3);
}).then(() => {
next();
}, e => {
res.json(error: e.message);
// better log this.
});
var rp = require('request-promise');
function handleError(err) {
res.json({
error: err.message
});
}
function parse(data) {
if (data) {
return JSON.parse(data);
}
}
rp(option1)
.then(parse)
.then(function (data) {
if (!data || !data.valid) {
throw Error('Error2');
}
if (data.expired) {
return;
}
return option2;
})
.then(rp)
.then(parse)
.then(function (data2) {
if (!data2 || !data2.valid) {
throw Error('Error1');
}
return option3;
})
.then(rp)
.then(parse)
.then(function () {
next();
})
.catch(handleError);
You don't need to manually check for statusCode but if you need to do so, first you have to add resolveWithFullResponse attribute to your option1 object, which allows you to receive the response object:
function checkStatusCode(response) {
if (response.statusCode !== 200) {
throw Error('Error3');
}
return response.body;
}
// add resolveWithFullResponse attribute to option1
option1.resolveWithFullResponse = true;
rp(option1)
.then(checkStatusCode)
.then(parse)
//...
Node.js:
var https = require("https");
var request = https.get("google.com/", function(response) {
console.log(response.statusCode);
});
request.on("error", function(error) {
console.log(error.message);
});
If I add https:// to the google domain name then I get the status code 200 as expected. As is, I would expect the error to be caught and an error message similar to "connect ECONNREFUSED" to be printed to the terminal console. Instead it prints the stacktrace to the terminal.
If you look at the source for https.get(), you can see that if the parsing of the URL fails (which it will when you only pass it "google.com/" since that isn't a valid URL), then it throws synchronously:
exports.get = function(options, cb) {
var req = exports.request(options, cb);
req.end();
return req;
};
exports.request = function(options, cb) {
if (typeof options === 'string') {
options = url.parse(options);
if (!options.hostname) {
throw new Error('Unable to determine the domain name');
}
} else {
options = util._extend({}, options);
}
options._defaultAgent = globalAgent;
return http.request(options, cb);
};
So, if you want to catch that particular type of error, you need a try/catch around your call to https.get() like this:
var https = require("https");
try {
var request = https.get("google.com/", function(response) {
console.log(response.statusCode);
}).on("error", function(error) {
console.log(error.message);
});
} catch(e) {
console.log(e);
}