Routing With Middleware checks based req.query
how to choose the next() based on req.query property
Example:
const preQueryCheck = (req,res,next)=>{
//??
}
Router.route(‘/add/:id’).post(preQuerycheck,addsum)
What I want is if req.query = type:sum
I want it to go to addsum
If it’s subtract it shd go to subtract !!
Is it possible ?
Here is example of writing your own middleware:
var express = require('express')
var app = express()
var myLogger = function (req, res, next) {
console.log('LOGGED')
next()
}
app.use(myLogger)
app.get('/', function (req, res) {
res.send('Hello World!')
})
app.listen(3000)
So in this case the middleware function is myLogger!
Related
I am writing APIs and wanted to understand what is a good way to add middleware shared by multiple routes. The middlewares does the same things in each route, like validating hosts/ip, validate user, etc.
The req object gets loaded with other objects in each of the middlewares like req.host, req.ip, req.username etc.
app.post("/route1", middleware1, middleware2, middleware3, middleware4);
app.post("/route2", middleware1, middleware2, middleware3, middleware4);
const middleware1 = (req, res, next) => {
// does something to validate user
req.username = "username"
next();
}
const middleware2 = (req, res, next) => {
// host validation
req.host = "something modified in validation"
next();
}
const middleware3 = (req, res, next) => {
// checks for mac and ip
req.mac = "mac addr"
next();
}
const middleware4 = (req, res, next) => {
res.send();
}
Or something like this:
app.post("/route1", middleware1);
app.post("/route2", middleware1);
const middleware1 = (req, res) => {
// does something to validate user
req.username = "username"
middleware2(req, res);
}
const middleware2 = (req, res) => {
// host validation
req.host = "something modified in validation"
middleware3(req, res);
}
const middleware3 = (req, res) => {
// checks for mac and ip
req.mac = "mac addr"
middleware4(req, res);
}
const middleware1 = (req, res) => {
res.send();
}
Thanks.
Generally I wouldn't call middlewares directly from another middleware. It mixes responsibilities of middleware logic and where the middleware is used.
Express is much more configurable than you think though. You can also install common middlewares in common paths:
If all routes use the middlewares:
// How common middlewares are normally installed:
app.post(middleware1);
app.post(middleware2);
app.post(middleware3);
app.post(middleware4);
// Alternative, less common way to do it:
app.post(middleware1,middleware2,middleware3,middleware4);
If only a specific pattern of urls use the middlewares:
// Use a regexp:
app.post(/route(1|2)/, middleware1, middleware2, middleware3, middleware4);
// Or if you don't like regexp, use globs:
app.post('route*', middleware1, middleware2, middleware3, middleware4);
// Or a more specific glob pattern:
app.post('route1?2?', middleware1, middleware2, middleware3, middleware4);
If all url in a subpath use the middlewares. For example, lets say if all urls in /route/... use the middlewares:
const route = express.Router();
app.use('/route',route);
route.post(middleware1);
route.post(middleware2);
route.post(middleware3);
route.post(middleware4);
If none of the above appeal to you you can still use your second option but instead of calling middlewares inside each other you write a middleware to initialize middlewares:
function commonMiddlewares (req, res, next) {
middleware1(req,res,function() {
middleware2(req,res,function() {
middleware3(req,res,function() {
middleware4(req,res,next);
});
});
});
}
Which can be written in a less nested way:
function commonMiddlewares (req, res, next) {
function runMiddleware4 () {
middleware4(req,res,next);
}
function runMiddleware3 () {
middleware3(req,res,runMiddleware4);
}
function runMiddleware2 () {
middleware2(req,res,runMiddleware3);
}
middleware1(req,res,runMiddleware2);
}
const express = require('express')
const { routesMiddleware } =require('./middlewares')
const { pureVaidationsFunctions1 } =require('./services')
const rout1 =express.Router()
const rout2 =express.Router()
const app = express()
app.use('/route1',route1)
app.use('/route2',route2)
// routesMiddleware a middleware to handle the execution of list of functions
// pureVaidationsFunctions1 list of funtions that `routesMiddleware` will consume
route1.post(routesMiddleware(pureVaidationsFunctions1))
route2.post(routesMiddleware(pureVaidationsFunctions2))
make sense?
You can specify multiple middlewares, see the app.use docs:
An array of combinations of any of the above.
You can create a file of all middlewares like -
middlewares.js
module.exports = [
function(req, res, next){...},
function(req, res, next){...},
function(req, res, next){...},
.
.
.
function(req, res, next){...},
]
and as then simply add it like:
/*
you can pass any of the below inside app.use()
A middleware function.
A series of middleware functions (separated by commas).
An array of middleware functions.
A combination of all of the above.
*/
app.use(require('./middlewares.js'));
Note - Do this only for those middlewares which will be common for all such requests.
I have two middleware functions attached to my app get request which works fine.
const express = require('express');
const app = express();
function fun1 (req, res, next) {
console.log('this is fun1')
next()
}
function fun2 (req, res, next) {
console.log('this is fun2')
next()
}
app.get('/', fun1, fun2, function (req, res, next) {
res.send('User Info')
})
app.listen(8080, () => console.log(`Listening on port 8080!`))
Now if I try to do next('test') in fun1 then it bypass fun2 and does 'test' output in browser window instead of 'User Info' which is correct. But how do I get data in fun2? I need to pass something from fun1 and get it in fun2 for further validation.
Assign it to req. You will have access to the same request and response objects through all middlewares.
Note that next('test') does not respond to the client or at least it is not meant to. It is meant to handle errors. Without an error handler and in development mode, Express shows these errors in the browser.
Read on:
Error handling in Express
You can do this by attaching a key-value pair with req` object.
Now how to do this,
const express = require('express');
const app = express();
function fun1 (req, res, next) {
req.MY_VAR = 'MY_VAL'; // setting the value
console.log('this is fun1')
next()
}
function fun2 (req, res, next) {
let myVar = req.MY_VAR; // retrieving the value
console.log(myVar); // MY_VAL
console.log('this is fun2')
next()
}
app.get('/', fun1, fun2, function (req, res, next) {
res.send('User Info')
})
app.listen(8080, () => console.log(`Listening on port 8080!`))
Now, why not next()? Generally, the value passed in next() will be received by the error argument in app.get('/', function (err, req, res, next) {} );
I am using the express framework for a node.js backend server. I am using the express router to define the different routes.
This is my app.js file:
var express = require('express');
var app = express();
var server = require('http').Server(app);
var cors = require('cors');
app.use(cors());
app.use(express.json());
var route = require('./route');
app.use('/api/', route);
server.listen(3000, () => {
console.log('App running on port 3000!');
});
This is my router route.js:
var express = require('express');
var router = express.Router();
var controller = require('./controller');
router.use(function (req, res, next) {
next();
router.get('/test', function (req, res, next) {
controller.get(req, res, next);
});
});
module.exports = router;
The route itself uses a controller for the logic controller.js
exports.get = function (req, res, next) {
res.send('Hello World');
}
Starting the app with node app.js and calling the defined route http://localhost:3000/api/test will result in a Cannot GET /api/test on the first try. Calling the route a second time however will result in the expected answer hello world.
What is the reason for the first call failing? Why does it work on the second try? Any ideas are appreciated
Because router.use(function (req, res, next) { will only get executed on the first request, and when you call next() the route was not yet added. Afterwards you call router.get(...) which will add the route, so it will be available the next time.
Nevertheless thats just bad, move the .get(...) outside of .use(...) (you can also get rid of it entirely).
I'm creating my routes module in nodejs with socket.io
var express = require("express"); // call express
var taskSchema = require("../models/taskModel");
var mongoose = require("mongoose");
var router = express.Router(); // get an instance of the express Router
module.exports = function (io) {
router.use(function (req, res, next) {
io.sockets.emit('payload');
console.log("Something is happening.");
next();
});
router
.route("/tasks")
.post(function (req, res, next) {
...
});
router
.route("/tasks")
.get(function (req, res) {
...
});
};
When I compile server I get this error
TypeError: Router.use() requires a middleware function but got a undefined
It appears to me that the problem is probably in the code that loads this module because you never export the actual router. So, assuming you do app.use() or router.use() in the caller who loads this module, your aren't returning the router from your function so there's no way to hook that router in and you would get the error you see.
I'm guessing that you can fix this by just returning the router from your exported function:
var express = require("express"); // call express
var taskSchema = require("../models/taskModel");
var mongoose = require("mongoose");
var router = express.Router(); // get an instance of the express Router
module.exports = function (io) {
router.use(function (req, res, next) {
io.sockets.emit('payload');
console.log("Something is happening.");
next();
});
router
.route("/tasks")
.post(function (req, res, next) {
...
});
router
.route("/tasks")
.get(function (req, res) {
...
});
return router; // <=========== Add this
};
Then, when you do:
let m = require('yourModule');
router.use(m(io));
Then function will return the router that router.use() will be happy with. You can pass either middleware or a router to .use().
If this guess isn't quite on target, then please show us the code that loads and calls this module.
When that function is called it's gonna return the equivalent of undefined. Also, normally a route is defined before the endpoint. It's typically structured like:
let myRouter = new Router();
Router.use('something', middlewareFunction, someotherprocess);
So I'm trying to seperate my login routes in a seperate JS file called login_routes.js
I keep getting this specific error:
TypeError: Router.use() requires middleware function but got a Object
at Function. (/Users/ethanthomas/Desktop/mean-stuff/express-server/node_modules/express/lib/router/index.js:446:13)
Not entirely understanding what it's asking me to implement?
login_routes.js:
var express = require('express');
var app = express();
app.route('/login')
.get(function(req, res, next) {
res.send('this is the login form');
})
.post(function(req, res, next) {
console.log('processing');
res.send('proccessing the login form!');
});
server.js:
var express = require('express');
var app = express();
var path = require('path');
var adminRoutes = require('./app/routes/admin_routes');
var loginRoutes = require('./app/routes/login_routes');
app.use('/admin', adminRoutes);
app.use('/login', loginRoutes);
//send our index.html file to the user for the home page
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
//start the server
app.listen(1337);
console.log('leet is the magic port');
Your login_routes.js should look something like this (in the context of express):
var express = require('express');
var router = express.Router();
// GET request to /login
router.get('/', function(req, res, next) {
// do something
});
// POST request to /login
router.post('/', function(req, res, next) {
// do something
});
module.exports = router;
In your app.js you use
var login_routes = require('./login_routes');
...
app.use('/login', login_routes);
...
Have a look at the code generated by the express-generator module. That is a starting point for express webserver apps.
People have already offered hints at the solution in comments.
The first issue is that you need to export your "sub" app from login_routes.js. To do so, change this:
var app = express();
Into this:
var app = module.exports = express();
Secondly, you are—probably unintentionally—creating routes for GET /login/login and POST /login/login. To solve this, use this in login_routes.js:
app.route('/').get(...).post(...);
This is because the root path in your sub app (the one in login_routes.js) will get mapped to the path used in app.use() in your main app (server.js).
Do like this:
login_routes.js:
exports.get = function( req, res ) {
res.send('this is the login form');
};
exports.post = function( req, res ) {
console.log('processing');
res.send('proccessing the login form!');
};
server.js:
var loginRoutes = require('./app/routes/login_routes');
app.get('/login', loginRoutes.get);
app.put('/login', loginRoutes.post);
login_routes.js:
var express = require('express');
var app = express();
app.route('/login')
.get(function(req, res, next) {
res.send('this is the login form');
})
.post(function(req, res, next) {
console.log('processing');
res.send('proccessing the login form!');
});
module.exports = router;
just writ module.exports = router then it will be work