Modify response body before res.send() executes in ExpressJS - javascript

In application which I currently develop, it's using Express. In my case I want to get response before it's been sent and modify it (for purpose of JWT). In this application, there is a dozen of endpoints and I don't want to create my own function like sendAndSign() and replace res.send() everywhere in code. I heard there is option to override/modify logic of res.send(...) method.
I found something like this example of modifying, but in my case this doesn't work. Is there any other option (maybe using some plugin) to manage this action?

You can intercept response body in Express by temporary override res.send:
function convertData(originalData) {
// ...
// return something new
}
function responseInterceptor(req, res, next) {
var originalSend = res.send;
res.send = function(){
arguments[0] = convertData(arguments[0]);
originalSend.apply(res, arguments);
};
next();
}
app.use(responseInterceptor);
I tested in Node.js v10.15.3 and it works well.

I have created an NPM package called experss-response-hooks that provides response hooks.
You can register a hook in a middleware before all your other routes, that will enable you to change the response body when send() will be called.
For example:
const responseHooks = require('express-response-hooks');
// response hooks initialization
app.use(responseHooks());
// register a middleware that modifies the response body before being sent to the client
app.use(function (req, res, next) {
// hook on "send()" function
res.hooks.on('send', (args) => {
args[0] = 'new-body'; // args[0] is the body passed to send()
});
});

Related

Use http.get Node.js with callback

I am trying to implement this library here, which generates QR codes and all other kinds of codes.
The problem I have is making a request where I have access to both req and res object, since I will need to pass these to the library. In the documentation, they are recommending
http.createServer(function(req, res) {
// If the url does not begin /?bcid= then 404. Otherwise, we end up
// returning 400 on requests like favicon.ico.
if (req.url.indexOf('/?bcid=') != 0) {
res.writeHead(404, { 'Content-Type':'text/plain' });
res.end('BWIPJS: Unknown request format.', 'utf8');
} else {
bwipjs.request(req, res); // Executes asynchronously
}
}).listen(3030);
The problem is I already have a server created, and I simply want to call the library in a get request, without creating another server. I have tried
http.get('http://localhost:3030/?bcid=azteccode&text=thisisthetext&format=full&scale=2', (req, res) => {
bwipjs.request(req, res); // Executes asynchronously
}
)
which obviously didn't work as the callback only takes response as an argument.
I would like to use bare node in the implementation as this is the way my server is implemented, and I don't want to add a library (like Express) just for this scenario.
You are heavily misunderstanding the role of http.get
http.get is used to do HTTP GET call to that certain url. It's basically what axios or request or ajax or xhr or postman or browser does.
The url param of http.get is not route. It's literally is the url you want to hit.
If you want to handle specific route you have to do it in the http.createServer() handler itself.
Like,
http.createServer(function(req, res) {
if (req.url.indexOf('/?bcid=') != 0) {
//do something
} else if (req.method == "get" && req.url.indexOf('/?bcid=') != 0){
bwipjs.request(req, res); // Executes asynchronously
} else {
//do something else
}
}).listen(3030);
Check out the req or http.IncomingMessage for available properties that you can use.

Is there an event emitted for socket.io ack/responses?

I'm using socket.io and express both with feathersjs. For metrics gathering I'm trying to capture round-trips for requests made both through Express as well as through socket.io.
The express side is easy with express middleware.
I can catch the socket.io inbound request via socket.use:
const app = express(feathers());
... (set up feathers services etc.)
app.configure(socketio(function(io) {
io.use(function(socket, next) {
socket.use((packet, next) => {
... (extract the verb and pathing info from the packet)
next();
});
next();
});
});
However, I can't find any equivalent of socket.use on the outbound/acknowledgement side. There's some events inside engine.io under the covers but I can't access them.
I'm really trying to find an equivalent set of events emitted for each request/response (the latter being the equivalent to finish in express).
I can't use connect/disconnect events here; I want to capture each request made over the socket and the responses sent for them, regardless of the feathers service and module.
Feathers.js hooks could be used for this, but it would require passing a bunch of context from the socket.io middleware into feathers, which I was hoping to not do.
Anyone know a way to do this?
In case anyone comes here looking for a way to do this, I'm not sure why I didn't think of it sooner.
The inbound packet (available in socket.use) will include a function as its last parameter if it should be acknowledged.
Wrapping the last function to inject my own logic worked.
pseudo-code
socket.use((packet, next) => {
const id = uuidv4();
console.log(`start of request: ${id}`);
const cb = packet[packet.length - 1];
if (typeof cb === 'function') {
packet[packet.length - 1] = function() {
const [err, data] = arguments;
console.log(`end of request: ${id}`);
if (err) {
console.error(err);
}
cb(err, data);
};
};
next();
});

Express routes and middleware

I'm using a role authorisation (connect-roles), and trying to add more than one role for each route. This is using express, and monogoose. Here is the code I currently have:
router.get('/admin/:slug', function (req, res) {
if (user.can('vip')) {
adminController.showVipView // <-- this is what I need to work
} else {
// call a different view
}
});
This is how it normally works without the if statement. This seems like super basic express, but I just cannot get it to work.
router.get('/admin/:slug', user.can('vip'), adminController.showVipView);
Just pass request and response into it:
adminController.showVipView(req, res);
It might also requires the next callback, then you should pass that into it too...
By the way, your if statement wont work either as it returns a middleware. Might do this:
user.can('vip')(req, res, function(){
adminController.showVipView(req, res);
});

Dynamic routing in Node.js

I want to create dynamic stubs as webservices. My idea is to load at every request a definition file and return data for corresponding URL.
The definition file could look like this:
/api/users {users:["john", "jack", "jake"]}
/api/users/1 {user:"john"}
/api/some-data/1 {data:"some data"}
In an application I created on behalf of a tutorial I find:
router.post('/some-irl', function (req, res) {
//some code
return {some JSON}
});
But this definition looks static to me, which should be there before I start Node.js Is it possible to define /some-irl at the time then request occures?
EDIT
Actually, I was intending to do somehting like this: https://github.com/typicode/json-server but it is already there!
You can attach a use middleware, which can check the path and decide whether to handle it or pass it on:
router.use(function(req, res, next) {
// req.path
// decide what to do
// respond or next()
});
you can define variables in the routes, use : before the variable name to define it, and then you'll get the value in req.params:
route.get('/api/users/:user/', function (req, res) {
var username = req.params.user;
});

Easy way to handle post data in meteor.js?

I need to handle some POST data in my meteor.js app, is there an easy way to do this?
Very basic, if it was a PHP app I would just want the $_POST variable.
Meteor router
https://github.com/tmeasday/meteor-router#server-side-routing
Meteor.Router.add('/items/:id', 'POST', function(id) {
// update Item Function
return [200, 'ok'];
});
If you are simply looking to intercept the GET and POST data, then send Meteor on it's merry way, you could do something like this on the server.
if (Meteor.isServer) {
var connect = Npm.require('connect');
var app = __meteor_bootstrap__.app;
var post, get;
app
// parse the POST data
.use(connect.bodyParser())
// parse the GET data
.use(connect.query())
// intercept data and send continue
.use(function(req, res, next) {
post = req.body;
get = req.query;
return next();
});
Meteor.startup(function() {
// do something with post and get variables
});
}
EDIT 11/01/13
I ended up creating a smart package for this (for myself). There is no documentation but you are welcome to use it. https://github.com/johnnyfreeman/request-data
To retrieve the foo request variable:
RequestData.get('foo') // --> 'bar'
RequestData.post('foo') // --> 'bar'
Both methods will throw a Meteor.Error if the key isn't found so make sure you use wrap with a try/catch if the variable is optional.
You can use Meteor's Iron Router, docs here, since Router (as mentioned above) is outdated and might be no longer functional.
Router.route('/items/:id', {where: 'server'})
.get(function () {
this.response.end('get request\n');
})
.post(function () {
this.response.end('post request\n');
});
I'm using this package to serialize body data: simple:json-routes. Here is the link.
And this code snippet to access it:
WebApp.connectHandlers.use('/api/request', (req, res, next) => {
console.log(req.body);
});

Categories

Resources