I am wondering how I can take and do something like return res.status(400).json({message: 'This is my message'}) in a controller/middleware then I want to be able to in a callback or another custom controller do res.render('test', {message}) where the message comes from my controller above. I am using EJS for my view engine which is where the {message} part comes from.
I have looked around online and on SO but have yet to find a good explanation of how to properly do this. I know that without the callback res.render part I can have my API work properly and returns the correct JSON to postman.
You can pass data from a middleware to a handler by putting the data in the req object. The middleware is defined as a function like (req, res, next) => { // Do stuff here}. Inside that you can do req.somePayloadIWantToPass = {hello: 'world'};
In your case, passing the information might look like this
const app = require("express")();
const port = 3000;
// Your middleware
app.use((req, res, next) => {
const payload = { message: "this is my message", statusCode: 400 };
req.payload = payload;
next();
});
// Your request handler
app.get("/", (req, res) => {
const { message, statusCode } = req.payload;
res.status(statusCode).render({ message });
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Notes
You can't use send multiple times for a certain request
Here we defined payload as a hard-coded variable, but you can define a certain logic to derive it from your request's body or parameters
Related
My client given me requirement to encrypt decrypt all request response. So for all encrypted request we wrote down the express middleware to get decrypted request. which is the simple part but while sending response we also have to encrypt response.
One way to do write common function to encrypt data and call that function from all routes. which is time consuming part because we have more than 50+ routes in project. So i was thinking to write middleware like we have done for request which capture response before we send and then we encrypt response after that we send encrypt response to client.
I have searched for solution in google not got any proper solution which worked for me.
routes.js
router.post('/getUserData', verifyApiKey, async function (req, res, next) {
let user = await getUserData();
res.status(200).send(user)
});
middlware.js
class EncryptDecryptRequestResponse {
async encryptResponse(req, res, next) {
console.log('Called encryptResponse');
console.log('res.body', res.body);
res.body = encryptData(res.body)
next();
}
}
App.js
// Middleware to decrypt request
app.use(decryptRequest);
app.use('/', indexRouter);
// Middleware to encrypt response
app.use(encryptResponse);
but the problem is that i am not getting any console.log from middleware. this is the solution which i used
I tried to reproduce the problem you're having with overwriting res.send(), but it works fine for me. You need to make sure to setup the interceptor middleware before you define your routes. Consider this simple example:
const express = require('express');
const app = express();
function encryptResponseInterceptor(req, res, next) {
const originalSend = res.send;
res.send = function () {
arguments[0] = encryptResponse(arguments[0]);
originalSend.apply(res, arguments);
};
next();
}
function encryptResponse(originalData) {
// place your encryption logic here, I'm just adding a string in this example
return originalData + " modified";
}
// fake method that returns resolves after 1s just for testing
function getUserData() {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000)
})
}
app.use(encryptResponseInterceptor);
app.get("/test", async (req, res, next) => {
await getUserData();
res.status(200).send("will be changed");
})
app.listen(3000, () => {
console.log("server started on 3000");
});
I'm running a standard NodeJs 8 with Express and currently when a request for an existing path but un-supported method comes in, Express return 404.
For example 'POST /login' is supported, but 'GET /login' is not, but it returns 404.
How can I make Express return 405 in such a case?
Here's the routes file:
const express = require('express');
const router = express.Router();
const loginController = require('../controllers/login');
router.route('/login').post(loginController.loginUser);
module.exports = router;
Please advise.
You can simply add the .all() handler to your route chain, like so:
const methodNotAllowed = (req, res, next) => res.status(405).send();
router
.route(`/login`)
.post(loginController.loginUser)
.all(methodNotAllowed);
Explanation
This works because requests are passed to the handlers in the order they are attached to the route (the request "waterfall"). The .post() handler will catch your POST requests, and the rest will fall through to the .all() handler.
Also see this question for more details.
Authenticating all POST routes
If you would like to ensure that the user is logged in for all POST requests, but return a 405 response for any other requests, you can use a regular expression to match all routes with router.post('*'), like so:
router
.post(`*`, loginController.loginUser)
.all(methodNotAllowed);
The problem with this approach, however, is that no 404 errors will ever be returned to the client, only 405. Therefore I recommend attaching the methodNotAllowed handler to each individual route, like in the first code snippet above. This approach will return 404 errors for routes that don't exist, but 405 errors for routes that do.
Determining the available methods for a route
To determine which methods are allowed for a route, use router.stack:
app.use((req, res, next) => {
const methods = router.stack
// Filter for the route that matches the currently matched route
.filter(layer => layer.route.path === req.path)[0]
.route
.methods;
if (!methods[req.method]) methodNotAllowed(req, res, next);
else next();
});
You can try this that way:
app.route("/login")
.get((req, res) => {
/* HANDLE GET */
})
.post((req, res) => {
/* HANDLE POST */
})
.all((req, res) => {
res.status(405).send();
});
How it works?
If request matches the route. It will go through the handlers. If a handler is present, it will be handled using that specific one. Otherwise, it will reach the 'all' handler that will set the status code to 405 and send the response.
Here You can find the discussion about it:
405 issue
#You question below:
You can try that way:
loginRoutes.js content:
const router = require('express').Router();
router.route('/')
.get((req, res) => {
res.status(200).send()
})
module.exports = router
server file content:
const express = require('express')
const app = express();
const router = express.Router();
const loginRoutes = require('./loginRoutes')
const PORT = process.env.PORT || 8080;
router.use('/login', loginRoutes)
router.route('/login').all((req, res) => { res.status(405).send() })
app.use(router);
app.listen(PORT, () => console.log(`started on port: ${PORT}`))
You can use this snippet of code to automatically send 405 status code when route from the same path exist but not with the current method
app.use(function (req, res, next) {
const AllLayers = app._router.stack
const Layers = AllLayers.filter(x => x.name === 'bound dispatch' && x.regexp.test(req.path))
const Methods = [];
Layers.forEach(layer => {
for (let method in layer.route.methods) {
if (layer.route.methods[method] === true) {
Methods.push(method.toUpperCase());
}
}
})
if (Layers.length !== 0 && !Methods.includes(req.method)) {
res.setHeader('Allow', Methods.join(','))
if (req.method === "OPTIONS") {
return res.send(Methods.join(', '))
}
else {
return res.sendStatus(405);
}
}
else {
next();
}
});
Hope this could be helpfull to someone
If you want to determine what methods COULD have been used you need to do a lot of digging in the app function you start your server with, and through some string manipulation and the like you can figure out what the possible methods are and return them in the error. If you're interested in how its done check out https://github.com/Justinlkirk/express-ez-405 or just use the npm package here https://www.npmjs.com/package/express-ez-405
I have the following node-mitm code.
mitm = Mitm();
mitm.on("request", function(req, res) {
const body = req.body; //body is null
})
I feel this has to do with reading node's IncomingMessage events, but I don't know how to do it.
Mitm.js's request handler is just like the one you're used to on Node's side. That is, it doesn't do anything special with req.body and leaves it as a ReadableStream.
You could either get its contents with the classical on("data") pattern:
mitm.on("request", function(req, res) {
req.on("data", function(data) { data == "Hello" })
})
If you want to fake a larger service, I've sometimes used Express to create routes and then pass Express's route handler to Mitm:
var Router = require("express").Router
var router = Router().use(require("body-parser").text())
router.get("/", function(req, res) { req.end() })
mitm.on("request", route.bind(null, router))
function route(router, req, res) {
router(req, res, function(err) {
if (err == null) return
res.writeHead(502)
throw err
})
}
The last example is a summary of the pattern I've also got publicly visible at the Rahvaalgatus open source repository: https://github.com/rahvaalgatus/rahvaalgatus.
Specifically, look at the controller test of https://github.com/rahvaalgatus/rahvaalgatus/blob/6dc91b026d75879cdc552bd2e63f220235b786c0/test/controllers/home_controller_test.js and see the this.router definition at https://github.com/rahvaalgatus/rahvaalgatus/blob/6dc91b026d75879cdc552bd2e63f220235b786c0/test/mitm.js.
Until now I've defined my get and post handlers with just (req, res) as arguments, with the assumption being that I put these handlers last in the chain of middleware, and make sure that I handle any responses and error handling properly within these handlers... hence it doesn't matter that I don't make any reference to next.
Is this a valid and sensible approach, or is it good practice always to call next() even if (at present) there is nothing coming afterwards? For example, perhaps in the future you might want to do some handling after these routes... or maybe there's a reason I haven't yet come across why it's good practice to always call next().
For example, there is the following simple example in the express routing guide:
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from B!')
})
Of course, I appreciate that this is a very simple example to illustrate that handlers can be chained, and is not intended to provide a complete framework for a get handler, but would it be better to define and use next even in the second handler, as follows?
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res, next) {
res.send('Hello from B!')
next()
})
Or is it actually common practice to assume that a handler function that sends a response back to the client should not call next()... i.e. the assumption should be that the chain will end at the handler that actually sends the response?
Or is there no established practice on this point?
I'm even wondering whether it might be common not to send any response in the get handler but to defer that to a dedicated response handler coming after... by which I mean an OK response handler rather than an error response handler (for which it seems to be common practice to defined a final error handler and call next(err)). So, in a non-error situation, you would call next() and in the following middleware you would do your res.status(200).send(req.mydata) where req.mydata is added in your get handler.
No. You should only call next() if you want something else to handle the request. Usually it's like saying that your route may match that request but you want to act like it didn't. For example you may have two handlers for the same route:
app.get('/test', (req, res, next) => {
if (something) {
return next();
}
// handle request one way (1)
});
app.get('/test', (req, res) => {
// handle request other way (2)
});
Always the first matching handler is called, so for the GET /test request the first handler will be called, but it can choose to pass the control to the second handler, as if the first didn't match the request.
Note that if the second handler doesn't intend to pass the request to the next handler, it doesn't even have next in its arguments.
If there was no second handler, then the standard 404 handler would be used if the first one called next().
If you pass an argument to next() then an error handling middleware will be called.
My rule of thumb is to handle the response in the handler if you're going to give a 20x (Success) response code, and in centralized error handling if not. That looks something like this in practice:
// ./routes/things.js
const express = require('express');
const Thing = require('../models/thing');
const Router = express.Router();
// note, the handlers might get pulled out into a controllers file, if they're getting more complex.
router.param('thingId', (req, res, next, id) => {
Thing.findById(id, (e, thing) => {
if (e) return next(e);
// let's say we have defined a NotFoundError that has 'statusCode' property which equals 404
if (!bot) return next(new NotFoundError(`Thing ${id} not found`));
req.thing = thing;
return next();
});
});
router.get('/', (req, res, next) => {
// possibly pull in some sort, limit, and filter stuff
Thing.find({}, (e, things) => {
if (e) return next(e);
res.send(things);
});
});
router.route('/:thingId')
.get((req, res) => {
// if you get here, you've already got a thing from the param fn
return res.send(req.thing);
})
.put((req, res, next) => {
const { name, description } = req.body; // pull whitelist of changes from body
let thing = req.thing;
thing = Object.assign(thing, { name, description }); // copy new stuff into the old thing
thing.save((e) => {
if (e) return next(e);
return res.send(thing); // return updated thing
});
});
Keeping each logical chunk in its own file can reduce repetition
// ./routes/index.js then mounts the subrouters to the main router
const thingsRoute = require('./things');
const express = require('express');
const router = express.Router();
/* .... other routes **/
router.use('/things', thingsRoute);
Error handling is then centralized, and can be mounted either in its own file or right on the app:
// in ./index.js (main app entry point)
const express = require('express');
// this will require by default ./routes/index.js
const routes = require('./routes');
const app = express();
const log = require('./log');// I prefer debug.js to console.log, and ./log.js is my default config file for it
/* ... other app setup stuff */
app.use(routes);
// you can mount several of these, passing next(e) if you don't handle the error and want the next error handler to do so.
app.use((err, req, res, next) => {
// you can tune log verbosity, this is just an example
if (err.statusCode === 404) {
return res.status(404).send(err.message);
}
log.error(err.message);
log.verbose(err.stack); // don't do stack traces unless log levels are set to verbose
return res.status(500).send(err.message);
});
I want to redirect from one URL request to another 'POST' request, like this:
var app = require('express')();
app.get('/', function(req, res) {
res.redirect('/test');
});
app.post('/test', function(req, res) {
res.send('/test page');
});
app.listen(3000, function() {
console.log('listenning on port:3000');
});
However, I can't redirect to '/test' page because it is a POST request. So what should I do to make the redirection work, keeping the '/test' request POST?
You can do this:
app.post('/', function(req, res) {
res.redirect(307, '/test');
});
Which will preserve the send method.
For reference, the 307 http code spec is:
307 Temporary Redirect (since HTTP/1.1) In this occasion, the request
should be repeated with another URI, but future requests can still use
the original URI.2 In contrast to 303, the request method should not
be changed when reissuing the original request. For instance, a POST
request must be repeated using another POST request.
For more info, see: http://www.alanflavell.org.uk/www/post-redirect.html
Keep in mind the middleware architecture: Each handler may manipulate the context, and either respond - or - call next().
By this premise, the express router is basically a middleware function you may use after "correcting" the url.
(BTW, the request app is also a function, although I'm not sure if I recommend going back so early in the chain)
Here's a kind'a example:
const router = new require('express').Router()
const user = require('../model/user')
//assume user implements:
// user.byId(id) -> Promise<user>
// user.byMail(email) -> Promise<user>
const reqUser = userPromise => (req, res, next) =>
req.user
? next()
: userPromise(req)
.then(user => { req.user = user })
.then(next, next)
//assume the sever that uses this router has a
//standard (err, req, res, next) handler in the end of the chain...
const byId = reqUser( req => user.byId(req.params.id) )
const byMail = reqUser( req => user.byMail(req.params.mail) )
router.post('/by-id/:id/friends',
byId,
(req, res) => res.render('user-friends', req.user)
)
router.post('/by-email/:email/friends',
byMail,
(req, res, next) => {
req.url = `/by-id/${req.user.id}/friends`
next()
},
router
)
The only difference between 307 and 302 is that 307 guarantees that the method and the body will not be changed when the redirected request is made.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307
I believe the question is that the node server is receiving a POST request but needs to redirect it to a different server as GET request. I recently had to deal with something similar. Here is how I solved it:
var proxy = require('express-http-proxy');
app.use('incomin/url', proxy('forwarding:server', {
//The proxyRqDecorator allows us to change a few things including the request type.
proxyReqOptDecorator: (proxyReqOpts, srcReq) => {
proxyReqOpts.method = 'GET';
return proxyReqOpts;
},
//The proxyReqPathResolver takes the Given URL and updates it to the forward path
proxyReqPathResolver: function (req) {
return new Promise( (resolve, reject) => {
setTimeout( () =>{
var value = req.body.key;
var resolvedPathValue = 'forwarding/url' + value;
console.log(`Inside forward path. The resolved path is ${resolvedPathValue}`);
resolve(resolvedPathValue);
}, 200);
});
}
}));
Keep in mind that the above proxyReqPathResolver is setup async. The synchronous vesrion and more info on express-http-proxy are described here:
https://www.npmjs.com/package/express-http-proxy