microservice with node and needle - node.js

I'm trying to make my monolithic application written in node and express to a microservice application in node, needle(to communicate between microservices) and express. My architecture is as follows,
I have a microservice called gateway_service to handle all the requests from frontend UI
I have another microservice called users_service to handle requests related to users, users_service uses passport local strategy to manage sessions and this session id is sent as a cookie by passport
When I try to change my application to microservice I'm doing the following
Whenever I receive a request from my client say, postman in gateway_service I can see the cookie coming through header, and I'm able to pass it to user_service by setting headers option as mentioned in needle.
How to send the cookie that I receive from user_service to the postman back to he can save the cookie(in case of first hit)??
I'm adding a small code snippet, hoping it will help?
Am I doing it in the right way??
when I'm doing as shown below Im getting the error "Cannot set headers after they are sent to the client"
function (req, res, next) {
var options = {
headers: req.headers,
parse_cookies:true
}
needle.post(url + "login", req.body, options, function (error, response, body) {
if (!error) {
res.writeHead(response.statusCode,response.headers);
res.send(body)
console.log(res);
next();
} else {
console.log("error in info from users micro service");
res.send(error);
next();
}
});
},

Related

Express Session and Request Modules

In my website, everything server-side is stored in sessions of express-session.
But I can't understand why, when I make an HTTP request with request module, the req.session parameter isn't within the request.
I mean, follow the comments :
app.get('/prefix', async function(req, res) {
console.log(req.session.login);
// There ^ the req.session.login is true, and so it works
if (req.session.login == false || req.session.login == null) return;
var options = {
url: 'https://bot-dreamsub.glitch.me/getPermission',
json: true,
jar: true,
withCredentials: true
}
request(options, async function(err, res, json) {
if (err) {
throw err;
}
console.log(json);
if (json == true) {
res.sendFile(__dirname + '/prefix/prefix.html');
} else {
return;
}
});
});
app.get('/getPermission', function(req, res) {
console.log(req.session.login);
// There ^ the req.session.login is undefined, and so it sends null to the user
try {
if (req.session.login == false || req.session.login == undefined) {
res.send(null);
} else {
// some other code
}
} catch(err) {
console.log(err);
};
});
I don't know why request doesn't send sessions within the HTTP request even with
withCredentials: true
What can I do to accomplish it?
An express-session works by setting a cookie in the client's browser that made the original request. Future requests with that same cookie will offer access to that same session. When you do request() yourself from your server, you aren't presenting the same cookie that came in with the original /prefix request so you won't have access to the same session.
Since it appears you are just trying to use request() to call your own server, I'd suggest you just use a function call and pass the original req.session to that function call so that you will have it available.
You then use normal code factoring to factor out some common code between your /getPermissions route and what you want to use in your /prefix route so that they can both use and share a common function that you pass the current req and res to. Then you don't need to solve this cookie issue because you'll already have the right req object and thus the correct req.session in this factored common function.
Alternatively, you could build the right cookie and send that with your request() so that it will appear to be coming from the original browser that has the cookie (and thus session) that you want, but that's kind of the long way to do things when you already have the req.session you want and you could just pass it in a function call rather than start all over and try to simulate a cookie that will get you to the right session.
I don't know why request doesn't send sessions within the HTTP request even with
First off, session aren't sent with a request. Cookies are. Your server then uses the cookie to find the right session object.
Your call to request() does not have the right cookie in the cookie jar you use so when that requests gets to your server, it isn't able to find the right session object. So, when the request is received by your server, it appears to be coming from a different client that does not yet have a session so a new cookie and a new session are probably created for it.
FYI, if also looks like you may be confusing two definitions of res in your request() call. There's a res defined as an argument in this app.get('/prefix', async function(req, res) { and then you have a separate res in request(options, async function(err, res, json) { that will override the previous one in that scope. It appears to me when you do res.sendFile(__dirname + '/prefix/prefix.html');, you are probably using the wrong res. Probably the best way to solve this is to not use request() at all as suggested above (using a function call to your own server). But, if you were going to still use request(), then you need to name the two res arguments differently so you can still access them both and can use the correct one for your situation.

Missing JSON data in External Api passed from Express JS

I have User Register page which is built with ExpressJS. The data entered here by the user should be passed over to an external Api (Java Rest Api). But I am not getting the JSON data at the receiving end. Also I have to send the response only after creating the User. Below are the code snippets:
Here is my ExpressJS code: (I am using Postman app to post the JSON data here)
router.post('/register', function(req, res, next) {
console.log(req.body); // JSON sent from Postman is showing correctly
var options = {
method: 'POST',
uri: 'http://localhost:3000/userCreation',
body: req.body,
json: true,
headers: { 'Content-Type': 'application/json' }
}
// Here rp is require('request-promise');
rp(options).then(function (res){
console.log("Response from external Api: "+res);
})
.catch(function (err) {
console.log(err);
})
// The response below should be ideally sent after the User Registration is done.
// So it should go into the "then" block. But I am an unable to put it there.
// It says "cannot send header twice"
res.send('Json Data sent to Java/MongoDB & User Created successfully.');
});
This is the code at the receiving end (Java API - but for now, I have another ExpressJS app to test the flow):
router.post('/userCreation', function(req, res, next) {
console.log("User registration in MongoDB");
console.log(req.hostname); // O/p : localhost
console.log(req.body); // O/p : undefined
res.send("User successfully created in MongoDB");
});
Any help/suggestion on this would be really helpful. Thanks in advance.
I got the answer..... "app.use(bodyParser.json())" was required at both the instances of the ExpressJS server. Now it is working fine.

"Error: Can't set headers after they are sent" in Express app with Node

I am new to Express and Node, and when testing a protected REST endpoint in my app using Advanced REST Client the data is returned from the endpoint to the Client as expected, however the console logs
"Error: Can't set headers after they are sent"
which stops the server. Searching here on SO, this seems to occur when sending more than one response but I don't see that in my code:
router.get('/books', userAuthenticated, function (req, res, next) {
Book.find({}, function(err, docs){
if(err) {
res.send(err)
} else {
res.send(docs);
// next();
// return;
}
})
});
Is this error expected when sending a request/response to/from the Client or am I missing something in handling the error on the server?
Express is a node.js server that features a concept called "middleware", where multiple layers of code get a chance to operate on a request.
In that case, not only do you need to check that your function is not sending back a response twice, but you have to check that other middleware are not sending back a response as well.
In your case, the code indicates that middleware called "userAuthenticated" is being invoked before this function. You should check if that middleware is already sending a response.
I don't think the problem was in the middleware. It looks like I was calling done() twice in passport deserialize. I commented out the first instance and the problem disappeared in all my routes. Although, I am not sure if I should comment out the first or second instance but I'll work on that next.
passport.deserializeUser(function(obj, done) {
console.log(obj);
Account.findById(obj, function(err, user) {
console.log(user);
//done(err, user);
});
return done(null, obj);
});

calling jasper report rest api through node js

I am very much new to the concept of jasper report. My team had already build some reports in jasperserver. the only thing I needed is to call reports. From a node server. I tried code from Jasper Rest API, run a report
router.get('/', function(req, res, next) {
request.post({url: "http://localhost:3030/jasperserver/rest/login",
qs: {j_username: "jasperadmin", j_password: "jasperadmin"}},
function(err, res, body) {
if(err) {
return console.error(err);
}
else{
request.get("http://localhost:3030/jasperserver/rest_v2/reports/SampleQueryReport.pdf",
function (error, response, body1) {
if (!error) {
console.log("downloading")
}
else{
console.log(response.statusCode);
console.log(error);
}
})
}
});
});
I want to get the report in pdf format. But when I tried this code am getting 401 unauthorized error.
I am using express js,node js,
npm module request, which I globally declared in app.js.
But I can log to the jasper soft directly with this credentials through url.
I understood what the problem was. It shows unauthorized error because in the second request it has no cookie. That is in the first request login take place and a cookie is generated. Which is not passed in the second request. So when I passed cookie with that request it worked. My mistake.

Connecting to a PHP website with Node.js and keep session

I'm making a testbench with Test'em and Mocha (that run on node.js) in order to test a PHP website.
What I want is to request some URL (e.g http://www.my-website/test.php) and get the http status code as well as the content returned.
I'm doing it with the node.js Request module.
The problem is:
I need to be authenticated to access this page, otherwise I'm
redirected to the login page.
So, does it exist a way to log in my application through Node.js and keep the session open to be able to chain tests on any pages I want?
I was thinking on get the PHPSESSID on login request if it is possible. Do you thing it is a good direction ?
Any help would be much appreciated.
Thank you, have a nice day :)
Michaël
If you set jar: true in your options or use your own custom cookie jar, then request will remember cookies set by the server so that you can keep your session between requests.
mscdex thanks for your answer! But unfortunately it did not work for me :/
hyubs thanks to you too.
Finally I carried on to use Mocha + Request.
Basically what I did is:
Connect through a POST request to the login page and get the PHPSESSID cookie that is returned in the response header.
Pass the cookie in the header in the next requests that target a URL where you have to be logged.
Here is my code :
var params = {
email: 'your_username',
password: 'your_password'
};
var paramsString = JSON.stringify(params);
// Login to the application
request.post('http://localhost/biings/front-end/rest/auth',
{
headers: {
"Content-Type" : "application/json",
'Content-Length' : paramsString.length
},
body: paramsString,
},function (error, response, body) {
// get the PHPSESSID (the last one) that is returned in the header. Sometimes more than one is returned
var sessionCookie = response.headers['set-cookie'][response.headers['set-cookie'].length - 1];
sessionCookie = sessionCookie.split(';');
sessionCookie = sessionCookie[0];
// Write it in a file (this is a quick trick to access it globally)
// e.g.: PHPSESSID=ao9a1j0timv9nmuj2ntt363d92 (write it simply as a string)
fs.writeFile('sessionCookie.txt', sessionCookie, function (err)
{
if(err)
{
return console.log(err);
}
});
});
// don't care about this it() function (it's for Mocha)
it("test 1", function(done)
{
// Get the cookie
fs.readFile('sessionCookie.txt','utf8', function (err, data)
{
if(err)
{
throw err;
}
else
{
// Launch a request that includes the cookie in the header
request.get('http://localhost/biings/front-end/rest/group',
{
headers: {"Cookie" : data},
}, function (error, response, body) {
// Check your request reaches the right page
expect(response.statusCode).equals(200);
console.log(body);
done();
});
}
});
});
It works like a charm for me.
Tell me if you see something wrong or which could be optimized :)
Michaël
Instead of using the request module, use headless browsers like PhantomJS and zombie.js. You can even emulate user interaction with these.

Resources