I had been trying to abort a request for hours, can anyone help me please?
This is what I have:
app.get('/theUrl', function (req, resp) {
var parser = new Transform();
parser._transform = function(data, encoding, done) {
var _this = this;
// Process data here
}.on("error", function(err){
console.log(err);
});
var theRequest = request({
'method' : 'GET',
'url': '/anotherUrl',
'headers' : {
"ACCEPT" : "text/event-stream"
}
}, function (error, response, body){
if (error) {
//Throw error
}
}).pipe(parser).pipe(resp);
req.on("close", function(){
parser.end();
theRequest.abort(); //Doesn't work
});
});
As you can see its kinda a streaming proxy, so if clients cancels the request I catch it and need to close or abort the forwarding request (theRequest).
Any ideas?
Thanks!
Quoting nylen from https://github.com/mikeal/request/issues/772#issuecomment-32480203 :
From the docs:
pipe() returns the destination stream
so you are no longer working with a Request object. In this case you're calling abort() on a ServerResponse. Do this instead:
var theRequest = request({ ... });
theRequest.pipe(parser);
theRequest.abort();
And everything worked.
Related
I have a sails.js service which uses restler (rest-client) to make api calls to external apis and fetch data.
The module looks like this:
var rest = require('restler');
module.exports = {
config: {
url: sails.config.remote_api.base_url.concat('/countries'),
rejectUnauthorized: sails.config.remote_api.validateSsl,
options: { 'Content-Type': 'application/json' }
},
find: function(headers, payload, callback) {
var request = rest.get(this.config.url, this.config.options);
sails.log.info('Outgoing Request', { log_id: headers[x - request - id], method: request.method, host: request.host, url: request.url });
request.on('2XX', function(data, response) {
callback(data, response);
});
}
}
In the above code request.on('2XX',...) handles the event emitted when response code is in the 200 series.
When we add other handlers for events emitted when response code is in 300, 400, 500 series...this creates a duplication of same callback function for each of the blocks. For e.g.
var rest = require('restler');
module.exports = {
config: {
url: sails.config.remote_api.base_url.concat('/countries'),
rejectUnauthorized: sails.config.remote_api.validateSsl,
options: { 'Content-Type': 'application/json' }
},
find: function(headers, payload, callback) {
var request = rest.get(this.config.url, this.config.options);
sails.log.info('Outgoing Request', { log_id: headers[x - request - id], method: request.method, host: request.host, url: request.url });
request.on('2XX', function(data, response) {
callback(data, response);
});
request.on('3XX', function(data, response) {
callback(data, response);
});
request.on('4XX', function(data, response) {
callback(data, response);
});
request.on('5XX', function(data, response) {
data = {};
data.succeeded = false;
data.failureCode = 'SYSTEM ERROR';
data.failureReason = 'A system error has occurred. Please try again. If the problem persists contact support';
callback(data, response);
});
request.on('error', function(data, response) {
data.succeeded = false;
data.failureCode = 'SERVICE UNAVAILABLE';
data.failureReason = 'The service is temporarily unavailable. Please try again later.';
callback(data, response);
});
}
}
How do we avoid the duplication of the following lines?
function(data, response) {
callback(data, response);
}
No you really shouldn't. You have been basically handling different event like 2XX, 3XX etc. Each event is handled separately and that is a good practice. Anymore simplification could damage the neat design.
Though you can directly use callback instead of
function(data, response) {
callback(data, response);
}
like this
request.on('2XX', callback);
Probably an obvious answer to this but I'm not sure what way to take.
request is a node module: https://github.com/request/request
I fill an array of getHistory requests (with different parameters). p = [p1,p2...].
this.app.all('/api/heatmap', function(req,res) {
// fill p here _.each(blabla, p.push(gethistory(someparams...)
var result = [];
function getHistory(params) {
var options = { ...};
var callback = function(error, response, body) {
if(error) { //wtv
} else {
// what to do with the body here ? return body ? result.push(body) ?
}
}
request(options, callback);
}
Q.all(p).then(function() {
});
}
So the problem here is that I when all of the request to be done , put everything in an array/object then send the whole thing to the client. How to have getHistory returning the fetched value (after the request is done ).
Hope it's clear.
The core problem here is that node.js-style callbacks and promises are not compatible. Promises emphasize on return values, node emphasizes on callbacks.
Therefore you need a sort of adapter that wraps node's callback convention properly, a process called Promisifcation. This can be done manually, but it's tedious at best and error-prone when you are not careful. Luckily, since node's conventions are well-established, it can be automated. Q has a few helpers for that, but Bluebird is quite a bit more convenient in this regard.
So the easy way to do it is to switch to Bluebird as the promise library and to use promisifyAll.
var Promise = require('bluebird');
var request = Promise.promisifyAll(require("request"));
this.app.all('/api/heatmap', function(req, res) {
var requests = blabla.map(function (item) {
return request.getAsync({ /* params */ });
});
Promise.all(requests).then(function (responses) {
res.send( JSON.stringify(responses) ); // whatever
}).catch(function (error) {
res.send( "An error ocurred: " + error ); // handle error
});
}
FWIW, here's another answer that shows how the same would look like when done properly with Q:
// promisified request
function requestAsync(options) {
var result = Q.defer();
request(options, function(error, response, body) {
if (error) {
result.reject(error);
} else {
result.resolve(body);
}
});
return result.promise;
}
// returns promises for heatmapVolumes
function getHistory(params) {
return requestAsync({
method: 'GET',
url: 'https://api.kaiko.com/v1/charts/' +
encodeURIComponent(params.exchange) + '/' +
encodeURIComponent(params.pair) +'/history',
qs: params.qs,
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
}).then(function (body) {
return heatmapVolume(body, params.exchange, params.pair);
}).catch(function (error) {
// log detailed error and send less revealing message downstream
console.error('error fetching trades', error);
throw new Error('Something went wrong while fetching trades');
});
}
// usage
this.app.all('/api/heatmap', function(req, res) {
getHistory({
exchange: "foo", pair: "bar", qs: "qux"
}).then(function (heatmap) {
res.send(200, heatmap);
}).catch(function (error) {
res.send(500, error);
});
});
Used Q.deferred and it worked as documented \o/
function getHistory(params) {
var deferred = Q.defer();
var options = {
method: 'GET',
url: 'https://api.kaiko.com/v1/charts/' + params.exchange + '/' + params.pair +'/history',
qs:qs,
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
}
var callback = function(error, response, body) {
if(error) {
console.log('error fetching trades', error);
res.send(500, 'Something went wrong while fetching trades');
} else {
var body = heatmapVolume(body, params.exchange, params.pair);
// console.log("result!", body.exchange, body.pair);
result.push(body);
// return body;
deferred.resolve();
}
}
request(options, callback);
return deferred.promise;
}
For a certain route, I have the following code:
router.get('/:id', function(req, res) {
var db = req.db;
var matches = db.get('matches');
var id = req.params.id;
matches.find({id: id}, function(err, obj){
if(!err) {
if(obj.length === 0) {
var games = Q.fcall(GetGames()).then(function(g) {
console.log("async back");
res.send(g);
}
, function(error) {
res.send(error);
});
}
...
});
The function GetGames is defined as follows:
function GetGames() {
var url= "my-url";
request(url, function(error, response, body) {
if(!error) {
console.log("Returned with code "+ response.statusCode);
return new Q(body);
}
});
}
I'm using the request module to send a HTTP GET request to my URL with appropriate parameter, etc.
When I load /:id, I see "Returned with code 200" logged, but "async back" is not logged. I'm also not sure that the response is being sent.
Once GetGames returns something, I want to be able to use that returned object in the route for /:id. Where am I going wrong?
Since GetGames is an async function write it in node.js callback pattern:
function GetGames(callback) {
var url= "my-url";
request(url, function(error, response, body) {
if(!error) {
console.log("Returned with code "+ response.statusCode);
return callback(null,body)
}
return callback(error,body)
});
}
Then use Q.nfcall to call the above function and get back a promise:
Q.nfcall(GetGames).then(function(g) {
})
.catch()
This is what my code looks like for a single http get request. What I want to do is call two more http get request and store their results so I can render appropriately. Can anyone please suggests how I can achieve it? Thanks
router.get('/get_all_posts', function(req, res){
var body ='';
var options = {
host: 'localhost',
path: '/some_endpoint',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
var request = http.request(options, function(response) {
response.setEncoding('utf8');
response.on('data', function (data_chunk) {
body += data_chunk;
});
response.on('end', function () {
if(response) {
res.render("something");
}
else
{
res.render('error', {error: {status:400,stack:body}});
}
});
});
request.end();
});
You should not be making http request. Whatever code you have for /some_endpoint turn it into a function, and then call that function inside router for both /some_endpoint and /get_all_posts.
Hope it helps.
This works for me.
async.map([options1, options2, options3], reqCall, function(err, results){
if ( err){
// do something
} else {
results[0]//first call
results[1]//second call
results[2] //third call
}
I want to get use this rest api with authentication. I'm trying including header but not getting any response. it is throwing an output which it generally throw when there is no authentication. can anyone suggest me some solutions. below is my code
var http = require('http');
var optionsget = {
host : 'localhost', // here only the domain name
port : 1234,
path:'/api/rest/xyz',
headers: {
'Authorization': 'Basic ' + new Buffer('abc'+ ':' + '1234').toString('base64')
} ,
method : 'GET' // do GET
};
console.info('Options prepared:');
console.info(optionsget);
console.info('Do the GET call');
var reqGet = http.request(optionsget, function(res) {
console.log("statusCode: ", res.statusCode);
res.on('data', function(d) {
console.info('GET result:\n');
process.stdout.write(d);
console.info('\n\nCall completed');
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.error(e);
});
The request module will make your life easier. It now includes a Basic Auth as an option so you don't have build the Header yourself.
var request = require('request')
var username = 'fooUsername'
var password = 'fooPassword'
var options = {
url: 'http://localhost:1234/api/res/xyz',
auth: {
user: username,
password: password
}
}
request(options, function (err, res, body) {
if (err) {
console.dir(err)
return
}
console.dir('headers', res.headers)
console.dir('status code', res.statusCode)
console.dir(body)
})
To install request execute npm install -S request
In your comment you ask, "Is there any way that the JSOn I'm getting in the command prompt will come in the UI either by javascript or by Jquery or by any means."
Hey, just return the body to your client:
exports.requestExample = function(req,res){
request(options, function (err, resp, body) {
if (err) {
console.dir(err)
return;
}
// parse method is optional
return res.send(200, JSON.parse(body));
});
};