Using Q promises in HTTP requests with NodeJs - node.js

I'm trying to make a chain of promises functions which use HTTP requests in NodeJS with Kraken framework.
My code could work in 90% of cases, but if the distant requested server takes time to respond, the code will return an error with undefined values. So I think Q is a good solution to prevent that.
Here's the situation :
We access to a URL with a "code" parameter -> the route controller takes this param to use it in a HTTP POST request -> the response (a token) is stored in a variable and used in an other HTTP GET request -> the response (multiple JSON objects) is stored in variable too -> all variables are stored in a MongoDB.
If functions are not used in this order, of course it fails.
var Q = require('q');
module.exports = function (router) {
router.get('/', function (req, res) {
var codein = req.param('code');
if(codein){
console.log('Provided code: ' + codein+'\n');
getAccessToken(codein).then(function(token){
console.log('Provided AccessToken: ' + token + '\n');
getUsername(token).then(function(userdata){
console.log('Provided Username: ' + JSON.parse(userdata).username + '\n');
storeData(userdata).then(function(msg){
console.log(msg);
res.redirect('/dashboard/' + JSON.parse(userdata).username);
});
});
});
}
else{
console.log('Access Denied, redirecting...');
res.redirect('/');
}
});
};
This method works, but actually didn't resolve the problem, because sometimes variable are undefined again. I think it's my request functions which aren't well made...
Here's an example of the first function with POST request :
var getAccessToken = function(cod){
var def = Q.defer();
var data = querystring.stringify({
client_id:"1234567890",
client_secret:"******",
grant_type:"authorization_code",
redirect_uri:"http://localhost:8000/r/callback",
code:cod
});
var options = {
host: 'domain.server.com',
port: 443,
path: '/api/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(data)
}
};
var response = "";
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
response += chunk;
});
res.on('end', function(){
var json = JSON.parse(response);
var acto = json.access_token;
def.resolve(acto);
});
});
req.write(data);
req.end();
return def.promise;
};
In this case the acto variable can be undefined... So am I using Q in a wrong way ?
EDIT
To understand my problem, let me show you what can I have in my output console (really rare but happens) :
Provided code: 12345678910
Provided Username: user543210
Instead of :
Provided code: 12345678910
Provided AccessToken: 9876543210
Provided Username: user

I think you need to account for 2 scenarios
Where the Twitch API takes time to respond.
The Twitch response cannot be parsed
The code
res.on('end', function(){
var json = JSON.parse(response);
var acto = json.access_token;
def.resolve(acto);
});
Should be modified as:
try {
var json = JSON.parse(response);
var acto = json.access_token;
//check if acto is undefined
if (acto === undefined) {
def.reject('Some error message');
} else {
def.resolve(acto);
}
} catch (error) {
//since the JSON could not be parse
def.reject(error);
}

Related

TypeError: Request path contains unescaped characters, any idea

//route to search (POST http://localhost:8080/api/search)
apiRoutes.post('/search', function(req, res) {
console.log('search');
var query = req.params;
console.log(query);
options = {
protocol : "https:/",
host: "https://api.themoviedb.org",
path: "/3/search/movie?api_key=35f7a26be584f96e6b93e68dc3b2eabd&language=en-US&page=1&include_adult=false&query="+query,
};
var req = https.request(options, function(res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.write("{}");
req.end();
})
DOES ANYONE KNOW WHERE THE PROBLEM IS?
I'm trying to do a request to do a research to the api the movie db and get the result back
There are some problems with the code. I have tested it and made it to work.
let options = {
host: "api.themoviedb.org",
path: "/3/search/movie?api_key=35f7a26be584f96e6b93e68dc3b2eabd&language=en-US&page=1&include_adult=false&query="+query.data.replace(' ','%20'),
};
first of all since you are using https module you don't need to specify the protocol nor you need to put it in the url. That's how your options variable should be.
Second you are appending the entire query object to the url which is {} instead you should append a string which will be in one of the key of your query object in my case its query.data
Third if there are spaces in the string Eg: Home Alone you to maintain space and avoid the error we replace the string with %20 which is a escaping character.
Forth Try giving a unique name for https request variable and its response variable in the callback function or it will override the route's req res variables cause your code to not work. Notice how I have used route's res function to send the data back and end the response
Also I am getting the data in req.body and you are using req.params however there are no params defined in your routes. Try going through the documentation for more information
Here is the complete code
apiRoutes.post('/search',function (req, res) {
https = require('https');
var query = req.body;
console.log(query.data);
let options = {
host: "api.themoviedb.org",
path: "/3/search/movie?api_key=35f7a26be584f96e6b93e68dc3b2eabd&language=en-US&page=1&include_adult=false&query="+query.data.replace(' ','%20'),
};
var request = https.request(options, function(response) {
var chunks = [];
response.on("data", function (chunk) {
chunks.push(chunk);
});
response.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
res.send(body);
res.end()
});
});
request.end();
});
Hope it helps.

How to make a form-data request with koa?

I am trying to replicate a login form's behaviour through koa.
The login form does:
<form id="loginForm" method="post" action="http://myaddress:3000/auth" enctype="multipart/form-data">
I'm using the koa request and form-data modules:
var form = new FormData();
form.append('identification', 'userId');
form.append('password', 'userPassword');
var options = {
url: DB_SERVER_URL + 'auth',
method: 'POST',
formData: form
};
var response = yield request(options);
console.log('response.statusCode: ' + response.statusCode);
But I always get a 400 response.
I've tried just using form.submit(DB_SERVER_URL + 'auth', function(err, res) { ... } which works, but I like koa's yield functionality and ideally I want to avoid having to deal with callbacks.
Any ideas?
Koa accepts multiple yield inputs that can be obtained from your current code more or less easily depending on your current setup:
a promise. As form-data doesn't seem to use them, we'll create one with Q
var Q = require('q');
var promise = Q.ninvoke(form, "submit", DB_SERVER_URL + 'auth');
var response = yield promise;
console.log('response.statusCode: ' + response.statusCode);
or a thunk, a wrapper function as you used in your answer, but there are libraries that can handle the wrapping for you (here, thunkify-wrap):
var thunkify = require('thunkify-wrap');
var submit = thunkify(form.submit, form); // the context is needed in this case
var response = yield submit(DB_SERVER_URL + 'auth');
console.log('response.statusCode: ' + response.statusCode);
I ended up using form.submit(DB_SERVER_URL + 'auth', function(err, res) { ... }, but wrapped the callbacks so I could use yield to maintain a synchronous control flow.
Here's my wrapper for the callback to the form.submit to receive the response:
function makeLoginRequest(formData) {
var form = new FormData();
form.append('identification', formData.identification);
form.append('password', formData.password);
var DB_SERVER_URL = 'http://myurl:3000/';
return function(callback) {
form.submit(DB_SERVER_URL + 'auth', function(error, response) {
callback(error, response);
});
}
}
And here's my wrapper for the callback for receiving the response body:
function getLoginResponseData(response) {
return function(callback) {
response.on("data", function(chunk) {
callback(null, chunk);
});
}
}
This lets me use yield to maintain a synchronous control flow:
var response = yield makeLoginRequest(this.request.body);
console.log('response.statusCode: ' + response.statusCode);
var chunk = yield getLoginResponseData(response);
console.log("BODY: " + chunk);
I'm a node and koa beginner, so if you have a better way please let me know!
If you are using koa-request I was able to do this.
const request = require('koa-request');
const response = yield request({
method: 'POST',
url: 'https://whatsever.com',
form: {
itema: 'vala',
itemb: 'valb',
},
headers: {
'Content-type': 'application/x-www-form-urlencoded'
}
});
this.body = response.body;
If you need multipart look here: https://www.npmjs.com/package/request#multipartform-data-multipart-form-uploads.
Remember that koa-request wraps therequest module

408 Timeout in NodeJS app requesting Github API

Following the documentation of the Github API to create an authorization for a NodeJS app.
I have the following code:
var _options = {
headers: {
'User-Agent': app.get('ORGANISATION')
},
hostname: 'api.github.com'
};
var oauth2Authorize = function () {
var path = '/authorizations?scopes=repo';
path += '&client_id='+ app.get('GITHUB_CLIENT_ID');
path += '&client_secret='+ app.get('GITHUB_CLIENT_SECRET');
path += '&note=ReviewerAssistant';
_options.path = path;
_options.method = 'POST';
var request = https.request(_options, function (response) {
var data = "";
response.on('data', function (chunk) {
data += chunk;
});
response.on('end', function () {
console.log(data);
});
});
request.on('error', function (error) {
console.log('Problem with request: '+ error);
});
};
And all I get is:
408 Request Time-out
Your browser didn't send a complete request in time.
Doing a GET request works though.
http.request() doesn't immediately send the request:
With http.request() one must always call req.end() to signify that you're done with the request - even if there is no data being written to the request body.
It opens the underlying connection to the server, but leaves the request incomplete so that a body/message can be sent with it:
var request = http.request({ method: 'POST', ... });
request.write('data\n');
request.write('data\n');
request.end();
And, regardless of whether there's anything to write() or not, you must call end() to complete the request and send it in its entirety. Without that, the server will eventually force the open connection to close. In this case, with a 408 response.

How to post the data in Node js

In my application i need to post the dynamic data into my main page(mani page means if i run my url(localhost:3456) in browser means that will display one page na that page).How can i post that data.I have tried this but i couldn't post the data.Can anyone help me to fix the issue.
app.js
var http = require('http');
var server = http.createServer(function(req, res){
res.writeHead(200, ['Content-Type', 'text/plain']);
res.write('Hello ');
res.end('World');
});
server.listen(3456);
postdata.js
var data={"errorMsg":{"errno":34,"code":"ENOENT","path":"missingFile.txt"},"date":"2013-0402T11:50:22.167Z"}
var options = {
host: 'localhost',
port: 3456,
path: '/',
method: 'POST',
data:data,
header: {
'content-type': 'application/json',
'content-length': data.length
}
};
var http=require('http');
var req;
req = http.request(options, function(res) {
var body;
body = '';
res.on('data', function(chunk) {
body += chunk;
});
return res.on('end', function() {
console.log('body is '+body);
});
});
req.on('error', function(err) {
console.log(err);
});
req.write(data);
req.end();
Do you have express installed along with Node, if so you can set up Rest Api's which you can use them in your jQuery and bind data dynamically. Please try to look into
http://expressjs.com/
Hope this helps.
//this is a string
var jsonString = '{"errorMsg":{"errno":34,"code":"ENOENT","path":"missingFile.txt"},"date":"2013-04-03T05:29:15.521Z"}';
//this is an object
var jsonObj = {"errorMsg":{"errno":34,"code":"ENOENT","path":"missingFile.txt"},"date":"2013-04-03T05:29:15.521Z"};
note the single quotes in for string
request.write(chunk, [encoding]) requires chunk to be either Buffer or string (see: http://nodejs.org/api/http.html#http_request_write_chunk_encoding)
Two things. First:
var data={"errorMsg:{"errno":34,"code":"ENOENT","path":"missingFile.txt"},"date":"2013-0402T11:50:22.167Z"}
is missing a double-quote, so it's invalid syntax... hence why the syntax highlighting is having trouble.
Second:
req.write(data);
should be:
req.write(JSON.stringify(data));
EDIT:
Based on your comment, I think you might be asking how to read from the body of an HTTP POST request (you're question is very ambiguously worded). If so, that's already very well documented in the Node.js API. Something along the lines of:
var server = http.createServer(requestHandler);
server.listen(3456);
function requestHandler (req, res) {
req.setEncoding('utf8');
var body = '';
req.on('data', function (chunk) { body += chunk; });
req.on('end', function () {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('The body of your request was: ' + body);
});
}
If that's not what you're asking, you'll need to clarify your question. Terms like 'main page' have no meaning unless you explicitly define what they are and what the expected outcome is.

Foursquare Check-in Reply

I am trying to Connect my application to foursquare and I want to display a message when a user checks in to certain places. I am trying to use their real time api https://developer.foursquare.com/overview/realtime
Everything works fine until the very end, ( when I have to send a reply post request https://developer.foursquare.com/docs/checkins/reply) I am using express and node.js. Here is what my post request looks like.
app.post('/handlepush', function(req, res) {
var checkin_id =req.param('checkin');
console.log(checkin_id);
var obj = JSON.parse(checkin_id);
var id = obj.id;
res.end('It worked!');
var token = "********************************";
var post_data = querystring.stringify({text : "awesome"});
var options = {
host: 'api.foursquare.com',
path: '/v2/checkins/' + id + '/reply?oauth_token=' + token,
port: 443,
method: 'POST'
};
var req2 = https.request(options, function(res2) {
res2.setEncoding('utf8');
res2.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
req2.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
});
req2.write(post_data);
req2.end();
});
this is the error I get, for some reason I am not able to add parameters for my post:
BODY: {"meta":{"code":400,"errorType":"other","errorDetail":"Must provide parameter text"},"response":{}}
You need to actually send your request. See: How to make an HTTP POST request in node.js?
var req2 = http.request(options, function(res2) {
res2.setEncoding('utf8');
res2.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req2.end();

Resources