Accessing Hapi request id without passing the request object everywhere? - node.js

I have a REST API written in Node.js/Hapi and I'm working on adding logging to it and integrating that to a centralized logging service like Splunk.
What I'd like to be able to do is write a simple logging util so that anywhere in the code I can do something like:
LoggingUtil.log('some message');
and the LoggingUtil would be able to figure out which request it pertains to and include that in the actual message that gets logged. That way when I search the logs the request id will tie together all the logs pertaining to a specific request.
I'm not super familiar with the event loop in Node and how I could accomplish this. The only thing I've found that might work is tick-id

I'm not sure exactly what you mean, but I give 2 suggestions based on whether you want logging all the time or just for debugging.
logging all the time example using Hapi's lifecycle method
server.ext('onRequest', (request, reply) => {
console.log(`\n++++++ ${request.raw.req.method} ${request.raw.req.url} ++++++\n`);
reply.continue();
});
onRequest means every time there is a request, this function is called. for mine I made it log the request method and URL. you can observe the request object to get the info you want.
logging only for debugging
basically same logic, pass the request object and access the info you need from there.
In your log function:
log(request) {
console.log(WHATEVER_YOU_NEED)
}

Related

Can't create a listener to the database while also being able to update it. (using References.on and References.put)

I'm trying to display a list of comments on my react page.
For this I have setup a NodeJS server which loads the data from Firebase and passes it on to React. I am able to get it to load the comments list and display them, but when I try to add a comment, the server crashes with the following error:
#firebase/database: FIREBASE WARNING: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
This is because I am using:
firebase.database().ref('my-path').on("value", ...)
However, if I use firebase.database().ref('my-path').once("value", ...) then I lose the ability to update the comments as soon as a new comment is posted. Is there a way to be able to have a listener attached to the database and still be able to update the contents of that database?
Here is my NodeJS code:
app.get("/comments/:id", (req, res) => {
const itemsRef = firebase.database().ref(`comments/${req.params.id}`);
itemsRef.on('value', (snapshot) => {
let comments = snapshot.val();
return res.status(200).json(comments);
})
})
app.post("/comments/:id", (req, res) => {
const itemsRef = firebase.database().ref(`comments/${req.params.id}`);
itemsRef.push(req.body);
})
The error occurs after the post request is called.
You're sending a response back to the client with:
res.status(200).json(comments)
This sets at least two headers (the status, and the response type) and then sends the response. Next time you get an update from the database, this code runs again, and again tries to send the two headers. But in HTTP all headers must be before the main body of the response. So the second time this code runs, it throws an error.
If you want to keep sending more data to the client, you'll need to use more primitive methods of the response object to prevent sending headers, or other illegal data. While possible, it's more complex than you may think, as the client needs to handle this response stream, which most clients won't.
I'd highly recommend looking at Doug's alternative, which is to just use the Firebase Realtime Database from the client directly. That way you can use the client SDK that it has, which handles this (and many more complexities) behind the scenes.

At what point are request and response objects populated in express app

I’m always coding backend api’s and I don’t really get how express does its bidding with my code. I know what the request and response objects offer, I just don’t understand how they come to be.
This simplified code for instance:
exports.getBlurts = function() {
return function(req, res) {
// build query…
qry.exec(function(err, results) {
res.json(results);
}
});
}
}
Then I’d call in one of my routes:
app.get('/getblurts/, middleware.requireUser, routes.api.blurtapi.getBlurts());
I get that the function is called upon the route request. It’s very abstract to me though and I don’t understand the when, where, or how as it pertains to the req\res params being injected.
For instance. I use a CMS that modifies the request object by adding a user property, which is then available globally on all requests made whether ajax or otherwise, making it easy at all times to determine if a user is logged in.
Are the req and res objects just pre-cooked by express but allow freedom for them to be modified to your needs? When are they actually 'built'
At its heart express is actually using node's default http-module and passing the express-application as a callback to the http.createServer-function. The request and response objects are populated at that point, i.e. from node itself for every incoming connection. See the nodeJS documentation for more details regarding node's http-module and what req/res are.
You might want to check out express' source code which shows how the express application is passed as a callback to http.createServer.
https://github.com/expressjs/express/blob/master/lib/request.js and https://github.com/expressjs/express/blob/master/lib/response.js show how node's request/response are extended by express specific functions.

Intercept user intent with `routing` middleware

I'm trying to intercept messages to send to my analytics server.
I'm looking to send it some data such as: messages,intent,resulted dialog.
I tried to use the routing middleware of universalBot in this fashion:
bot.on('routing',(session)=>{
console.log(session.intent);
console.log(session);
})
But it seems like the intent is undefined, and the only way I manage to see it is through triggerAction => onFindAction function.
I can use this method but it seems like a hack, is there a good way to intercept the intent data with middleware?
I'm using the Node.js SDK with botbuilder-apiai

How to send a http response using koajs

I'm trying to validate a webhook via facebook. So facebook hits my url my-url/facebook/receive within my route in nodejs i'd do res.send(req.query['hub.challenge']); to send an http response.
I'm using KoaJS. From what i understand, Koajs merges the request and response object into ctx but when reading through the docs I can't find anything along the lines of ctx.send or similar to send a http response.
Can anyone give me some direction or links.
Thanks.
To send the body of a response, you can simply do ctx.response.body = 'Hello'. There are many aliases attached to ctx, so you don't necessarily have to reference the response or request yourself. Doing ctx.body = 'Hello' would be the same as the code above.
If you wanted to set headers, you would use the ctx.set() method. For example: ctx.set('Content-Type', 'text/plain').
To access the query parameters, you would use ctx.request.query['some-key'] (or simply the alias ctx.query['some-key']).
All of the different request/response methods are documented pretty well at the Koa website along with a list of aliases attached to ctx. I highly recommend you give it a read.

Testing Express errors with Mocha and Supertest

I have to test for server errors (Express) in acceptance tests that can't (or shouldn't) be sent with response, for example
Error: Can't set headers after they are sent.
Catching an error with error handler and responding with 5XX code would provide valuable feedback here, but the problem is that the headers have been sent already.
This kind of bugs may be noncritical and hard to spot, and usually they are figured out from the logs.
The spec is
it('should send 200', function (done) {
request(app).get('/').expect(200, done);
});
And tested app is
app.get('/', function (req, res, next) {
res.sendStatus(200);
next();
});
app.use(function (req, res) {
res.sendStatus(200);
});
What is the most appropriate way to communicate between Express app instance and request testing library (i.e. Supertest) in similar cases?
The question is not restricted to Supertest. If there are packages that can solve the problem that Supertest can't, they may be considered as well.
Try to just set the status code without send it and avoid send it twice throwing the error use res.status().
As the express documentation say it
Sets the HTTP status for the response. It is a chainable alias of
Node’s response.statusCode.
IMHO if you want to detect it in a end-to-end (E2E) testing tool like supertest (or Selenium) you have to handle the express error and send a correct output (500 status error, some message...) to permit detect it.
Or use instead a unit test, to test that the controller function doesn't throw any error using chai or a native assertion.
I answered a similar question here. The "can't set headers after they have been set" error should be raised by express as an unhandled exception. So, you should be able to get access to it via the unhandledException event that is raised by the process.
However, this is much more tricky because of the timing. Your test case's expect function and done function will be queued for processing on the event loop on the tick right after the first res.statusCode call. Unfortunately, the next call for res.statusCode can happen at an indeterminate amount of time afterwards. For example, what if the second route handler called a really slow webservice or db and then called res.statusCode.
With that in mind, your options are pretty hard. The brute force way is to wait in your test code for a determinate amount of time and then check. It's effective but slow and non-deterministic, which will cause your test to be flaky.
Another option is to check any instrumentation code that you might have in express. If you have code in express that keeps metrics of the number of in process calls for the various route handlers you could expose these metrics to your test code. Then one of your conditions for finishing your test is that all metrics for in process route calls are 0. The second option would allow you to write deterministic tests and be much faster because you could poll the metrics.
The final option would be to handle this test case through unit tests. This is probably the best solution because it would be deterministic and wouldn't require any sort of polling. However, the downside is that you need to know that both of your functions are called in order which leads you down a path of trying to recreate in your test code the logic that express uses to call route handlers.
I did this using HAPI instead of Express, but I solved the same problem. I used an external library to make the call (like request-promise) and it worked. Catch the error in the request-promise response.

Resources