Dynamic post/put routing in ExpressJS - node.js

I'm using Angular on the client side, Express on the server. I've got two forms on the same page. I need both forms to post to the same URL, but use a different controller method, depending on a variable that I can grab from the request body.
Obviously the routes listed below would work individually, but since I need both, having two PUTs on the same URL won't work:
app.put('/articles/:articleId', articles.update);
app.put('/articles/:articleId', articles.addEditor);
In pseudo-express code, what I'd like is:
app.put('/article/:articleId', function(req) {
if (req.editor) {
articles.addEditor;
} else {
articles.update;
});

How about:
app.put('/article/:articleId', function(req, res, next) {
if (req.body.editor) {
articles.addEditor(req, res, next);
} else {
articles.update(req, res, next);
}
});

Related

How to routing for mobile view in express

I want to change the URL for mobile. www.example.com to m.example.com
I use isMobile function to detect device type.
I do not know what to do for routing.
for example: m.example.com/index
please help me
in app.js
function isMobile(req, res, next) {
if ((/Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(req.headers["user-agent"]))) {
res.redirect('//m.' + req.host+ req.path);
} else {
next()
}
}
app.get('/',isMobile,routes.index);
If device is a mobile,i want to run routes.mobileindex. How?
If you want to render a separate view for mobile devices in the same application then it would be pretty straigh forward. it is a just a matter of creating another view file and you can apply your separate layout and CSS style to design it.
var express = require("express");
var router = express.Router();
function isMobile(req, res, next) {
if (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(
req.headers["user-agent"]
)
) {
// Instead of redirecting to another view you can also render a separate
// view for mobile view e.g. res.render('mobileview');
res.redirect("/mobile/device");
} else {
next();
}
}
/* GET home page. */
router.get("/", function(req, res, next) {
res.render("index", {
title: "Express"
});
});
router.get("/device", isMobile, function(req, res, next) {
res.json("normal view is rendered");
});
router.get("/mobile/device", function(req, res, next) {
res.render("mobile");
});
module.exports = router;
I have set a redirection here but this is not the best way if you are in the same application, because you can directly hit /mobile/device view, in that case you also need a middleware or can reuse the isMobile middleware to redirect to normal view. I would rather suggest to use res.render('yourviewname')
Hope this gives you an idea to proceed futher!

Add header to all responses after processing but before sending to client

I have two endpoints in a node js app:
app.get('search', myGetController);
app.post('add', myPostController);
For simplicity, let's assume both services have only the following code:
exports.myGetController = function(req, res) {
res.status(404).json({ error: "not found" });
};
I want to have a middleware that is executed after the processing of the controllers, but before they are sent to the browser, so I can add a header based on the body of the response.
// process all responses to add ed25519
app.use(function(req, res, next) {
res.setHeader('CharCount', [How To get Body content]);
next();
});
I have two questions:
First of all, I would like to have all my controllers pass by that middleware after processing.
Second, I would like to access the body content so I can generate a header based on its content.
UPDATE
I have tried the suggested answer someone posted, and it is not working, or I am missing something.
This is what I have (before setting up my routes):
app.use(function(req, res, next) {
const oldResJson = res.json;
res.json = function(body) {
res.setHeader('myToken', generateHeaderBasedOnBody(oldResJson));
oldResJson.call(res, body);
}
next();
});
The response that is being passed to my method is an empty string, even though the response sent by the service is not empty. Am I doing this in the wrong place, or what am I missing?
One solution for this issue would be to override the res.json function like so:
// process all responses to add ed25519
app.use(function(req, res, next) {
const oldResJson = res.json;
res.json = function(body) {
res.setHeader('CharCount', /* Use body here */);
oldResJson.call(res, body);
}
next();
});
By doing this, you don't even need to change your controllers.

How to delegate route processing in express?

I have expressjs application with straitfort route processing like the following:
app.route('/').get(function(req, res, next) {
// handling code;
});
app.route('/account').get(function(req, res, next) {
// handling code;
});
app.route('/profile').get(function(req, res, next) {
// handling code;
});
At now I put all my code inside route handler but I want try to delegate it to some class such as the following.
app.route('/').get(function(req, res, next) {
new IndexPageController().get(req, res, next);
});
app.route('/account').get(function(req, res, next) {
new AccountPageController().get(req, res, next);
});
app.route('/profile').get(function(req, res, next) {
new ProfilePageController().get(req, res, next);
});
So what do you thing about the approach above and meybe you know the better one?
As you can see in the Express Response documentation - the response (req) can send information to the client by a few methods. The easiest way is to use req.render like:
// send the rendered view to the client
res.render('index');
Knowing this means that you can do whatever you want in another function, and at the end just call res.render (or any other method that sends information to the client). For example:
app.route('/').get(function(req, res, next) {
ndexPageController().get(req, res, next);
});
// in your IndexPageController:
function IndexPageController() {
function get(req, res, next) {
doSomeDatabaseCall(function(results) {
res.render('page', results);
}
}
return {
get: get
}
}
// actually instantiate it here and so module.exports
// will be equal to { get: get } with a reference to the real get method
// this way each time you require('IndexPageController') you won't
// create new instance, but rather user the already created one
// and just call a method on it.
module.exports = new IndexPageController();
There isn't strict approach to this. You can pass the response and someone else call render. Or you can wait for another thing to happen (like db call) and then call render. Everything is up to you - you just need to somehow send information to the client :)

Express, multiple routes to same function

I am mimicking another api. I would also like to provide a different (better IMHO) api as well.
// this is url I need to support
api.post('/books/updateBook', function(req, res) {
...
});
// Would also like to support
api.put('/books/:bookId', function(req, res) {
...
});
I could easily do:
var updateBook = function(req, res) {
...
}
// this is url I need to support
api.post('/books/updateBook', updateBook);
// Would also like to support
api.put('/books/:bookId', updateBook);
Perfectly acceptable right? Being new to express I am wondering if there is a more 'express' way to handle this. I know you can use regex, but I am not sure you can map regex across different HTTP verbs (POST vs PUT).
Thoughts?
api.all('/books/:bookId', function (req, res, next) {
if (req.method === 'PUT' || req.method === 'POST) {
//get your groove on
} else {
next();
}
});
You can combine verbs in express, you just use all and examine the method, if it matches, handle the request other wise pass it down the handler chain (with next();).
That being said I think you're doing it right, there's no reason route handlers need to be lamdas.

Calling to next middleware after redirect in Express.js

I am looking to drive behavior through integration tests on an Express.js middleware. I have encountered an interesting circumstance where the behavior of Express behind the application is not predictable (not by me, anyway).
As a simplified example:
var middlewareExample = function(req, res, next){
if(req.session){
refreshSession(req.session, function(err, data){
if(!err){
res.redirect('/error');
}
});
next();
}else{
res.redirect('/authenticate');
}
};
The issue is the call to next following the redirect, as it lives outside of the inner function and conditional. I am not certain how Express handles middleware/route calls to next or res.redirect if they happen to take place before or after one another as seen above.
Manual testing has not revealed any strange behavior, nor has the supertest module. I would like to know if and how Express responds to circumstances such as this. Also, can supertest can be used to expose any potential unwanted behavior. Additionally, if I may, I would like to hear what approaches others would use to test Node/Express middleware in general.
you are sending two responses in the same request. next() is a response, assuming the next handler has a response as well, and so is res.redirect(). What you really want is:
var middlewareExample = function(req, res, next){
if(req.session){
refreshSession(req.session, next);
}else{
res.redirect('/authenticate');
}
};
I was experiencing this issue with the below example.
const redirect = () => (res, resp, next) => {
if (/* redirect condition met */) {
return resp.status(302).redirect(`https://example.com/${path_logic()}`);
} else {
return next();
}
}
app.use(redirect());
app.get('*', static('built/project/code'));
I wasnt able to find anything talking about redirects not working in the .use method. But apparently it is not allowed.
Here is my solution.
const redirect = () => (res, resp, next) => {
if (/* redirect condition met */) {
return resp.status(302).redirect(`https://example.com/${path_logic()}`);
} else {
return next();
}
}
app.get('*', [
redirect(),
static('built/project/code')
]);
The only logic difference here is the redirection function only seem to work when combined with a request handler (.get .post etc), but not .use.

Resources