I want to just verify something but have't been able to find anything in the Express docs or online regarding this (although I know it's a feature).
I could just test this out but I don't really have a nice template and would like to hear from the community.
If I define a route in express like such:
app.get('/', function (req, res) {
res.send('GET request to homepage');
});
I can also define a middleware and load it directly, such as
middleware = function(req, res){
res.send('GET request to homepage');
});
app.get('/', middleware)
However, I can also chain at least one of these routes to run extra middleware, such as authentication, as such:
app.get('/', middleware, function (req, res) {
res.send('GET request to homepage');
});
Are these infinitely chainable? Could I stick 10 middleware functions on a given route if I wanted to? I want to see the parameters that app.get can accept but like mentioned I can't find it in the docs.
Consider following example:
const middleware = {
requireAuthentication: function(req, res, next) {
console.log('private route list!');
next();
},
logger: function(req, res, next) {
console.log('Original request hit : '+req.originalUrl);
next();
}
}
Now you can add multiple middleware using the following code:
app.get('/', [middleware.requireAuthentication, middleware.logger], function(req, res) {
res.send('Hello!');
});
So, from the above piece of code, you can see that requireAuthentication and logger are two different middlewares added.
It's not saying "infinitely", but it does say that you can add multiple middleware functions (called "callbacks" in the documentation) here:
router.METHOD(path, [callback, ...] callback)
...
You can provide multiple callbacks, and all are treated equally, and behave just like middleware, except that these callbacks may invoke next('route') to bypass the remaining route callback(s). You can use this mechanism to perform pre-conditions on a route then pass control to subsequent routes when there is no reason to proceed with the route matched.
As you can see, there's not distinction between a middleware function and the function that commonly handles the request (the one which is usually the last function added to the list).
Having 10 shouldn't be a problem (if you really need to).
Express version "express": "^4.17.1" or above
From the document: Series of Middleware
var r1 = express.Router();
r1.get('/', function (req, res, next) {
next();
});
var r2 = express.Router();
r2.get('/', function (req, res, next) {
next();
});
app.use(r1, r2);
Let's try a real life example:
tourController.js
exports.checkBody = (req, res, next)=>{ // middleware 1
if (!req.body.price){
return res.status(400).json({
status:'fail',
message:'Missing price!!!'
})
}
next();
}
exports.createTour = (req, res) => { // middleware 2
tours.push(req.body);
fs.writeFile(
`${__dirname}/dev-data/data/tours-simple.json`,
JSON.stringify(tours),
(err) => {
res.status(201).json({
status: 'success',
data: {
tour: newTour,
},
});
}
);
};
tourRouter.js
const express = require('express');
const tourController = require('./../controller/tourController')
const router = express.Router();
router.route('/')
.get(tourController.getAllTours)
.post(tourController.checkBody, tourController.createTour);
//muliple Middleware in post route
module.exports = router //need this or the following step will break
app.js
const express = require('express');
const tourRouter = require('./route/tourRouter');
const app = express();
app.use(express.json());
app.use('/api/v1/tours', tourRouter);
module.exports = app;
Related
In Express.js, ihave been having problems with making my own middleware. I know that middleware is supposed to be a function, but can the middleware function be inside an array.
For Example:
module.js:
module.exports = {
function1: function(req, res) {
console.log('function1');
//second edit.
I want to return something as well
return 'hello world';
//if i add next(); it wont call the next();
},
function2: function(req, res) {
console.log('function2');
}
}
app.js:
const express = require('express')
, middleware = require('./module')
, app = express();
app.use(middleware.function1);
app.use(middleware.function2);
app.get('/', (req, res) => {
//this is an edit: i want to use some code here like
res.send('Hello World');
middleware.function1();
});
app.listen(8080);
When i Do This, the webpage just doesn't load. Any Help?
You are missing crucial part next function (which is callback to trigger next middleware in the sequence) in defining middleware functions function1 and function2.
Have you seen https://expressjs.com/en/guide/writing-middleware.html ?
In below code, you are not passing req, res to the middleware function.
app.get('/', (req, res) => {
middleware.function1();
});
OR call it directly as below
app.get('/', middleware.function1);
I am trying to learn Express for NodeJS but I came across this:
I am trying to add 2 middlewares depeding on url, so on the /user to do something and on root to do something different. However the root middleware is always called even if i dont use next() and if i access the "/" url, the root middleware is called twice.
const express = require('express');
const app = express();
app.use('/user', (req, res, next) => {
console.log('In user middleware ');
res.send('<h1>Hello from User page</h1>');
});
app.use('/', (req, res, next) => {
console.log('In slash middleware !');
res.send('<h1>Hello from Express !</h1>');
});
app.disable('etag');
app.listen(3000);
it should be get or post not use
-get or post are routes
-use is middleware function
check this
const express = require('express');
const app = express();
app.get('/user', (req, res, next) => {
console.log('In user middleware ');
res.send('<h1>Hello from User page</h1>');
});
app.get('/', (req, res, next) => {
console.log('In slash middleware !');
res.send('<h1>Hello from Express !</h1>');
});
app.disable('etag');
app.listen(3000);
From an issue at GitHub.com
https://github.com/expressjs/express/issues/3260
Hi #davidgatti my "root path middlware" I assume you are talking about
nr_one. If so, yes, of course it is executed on every request; app.use
is a prefix-match system. Every URL starts with /, so anything mounted
at / will of course get executed :)
Okay, I can't confirm this but I suspect from the tutorial you are following you might be missing a line.
As you said, app.use is a middleware which will be added to all the route
So when you load say some url where you expect the middleware then it won't know about the request type (post, put, delete or get request).
Any alternate for this could be to try something like this
app.use('/user', (req, res, next) => {
if (req.method === 'GET') {
console.log('In user middleware ');
res.send('<h1>Hello from User page</h1>');
}
});
Again, Just check and compare his code thoroughly
Adding this link from Justin's answer for reference
In order to avoid such a problem, you have to use the return keyword.
When you send a file to the server, use return.
Try the following code,
const express = require('express');
const app = express();
app.use('/user', (req, res, next) => {
console.log('In user middleware ');
return res.send('<h1>Hello from User page</h1>');
});
app.use('/', (req, res, next) => {
console.log('In slash middleware !');
return res.send('<h1>Hello from Express !</h1>');
});
app.disable('etag');
app.listen(3000);
At line 13 and 8, I used the return keyword.
So when you make http://localhost:3000/ request, you will receive
Hello from Express !
And whenever you make http://localhost:3000/user request, you will receive
Hello from User page
What I want to do
if req is from mobile
first check these routes
router.use('/', mobileRoutes);
then ones below
router.use('/', routes);
but as far as I understand express goes through all use statements upon every request, it runs them all once and put route handlers into some sort of array. that get hit with requests.
For some urls I want to server different pages but no all (loginPage, registrationPage, etc).
Is it possible to do conditional routing, to prepend more routes in case some condition is met.
What I do have working is this:
router.use(function (req, res, next) {
let md = new MobileDetect(req.headers["user-agent"]);
if (md.mobile()) {
req.url = '/mobile'+req.url;
}
next();
});
//mobile routes
router.use("/mobile", require("./mobile"));
but it completely blocks all routes below.
I want a clean solution, One another option, which is not clean, is to add middleware to individual routes but that muddies code endlessly.
My Solution for conditional routing:
index.js
.....
//mobile routes
router.use("/", require("./mobile"));
router.get("/", require("./get"));
.....
mobile.js
const express = require("express");
const router = express.Router();
const MobileDetect = require("mobile-detect");
router.use(function (req, res, next) {
let md = new MobileDetect(req.headers["user-agent"]);
(md.mobile())? next() : next("router")
});
router.get("/", function (req, res) {
res.send({ query: req.query });
});
module.exports = router;
what I want it to do.
router.post('/xxxx', authorize , xxxx);
function authorize(req, res, next)
{
if(xxx)
res.send(500);
else
next();
}
I want to check for session in each route.
But since the routers are written in this way.
router.route('/xxx/xxxx').post(function(req, res) {
// blah lah here...
//
});
So how can I set up a middleware that will check for session and I wanted to make things a bit more generic and wanted to have a single authorize function doing a single thing instead of checking in every request.Any suggestions.
Define a middlware function before you define / include your routes, this will avoid you checking for a valid session in every route. See code below for an example on how to do this.
If some routes are public, i.e. they do not require a user to have a valid session then define these BEFORE you 'use' your middlware function
var app = require("express")();
//This is the middleware function which will be called before any routes get hit which are defined after this point, i.e. in your index.js
app.use(function (req, res, next) {
var authorised = false;
//Here you would check for the user being authenticated
//Unsure how you're actually checking this, so some psuedo code below
if (authorised) {
//Stop the user progressing any further
return res.status(403).send("Unauthorised!");
}
else {
//Carry on with the request chain
next();
}
});
//Define/include your controllers
As per your comment, you have two choices with regards to having this middleware affect only some routes, see two examples below.
Option 1 - Declare your specific routes before the middleware.
app.post("/auth/signup", function (req, res, next) { ... });
app.post("/auth/forgotpassword", function (req, res, next) { ... });
//Any routes defined above this point will not have the middleware executed before they are hit.
app.use(function (req, res, next) {
//Check for session (See the middlware function above)
next();
});
//Any routes defined after this point will have the middlware executed before they get hit
//The middlware function will get hit before this is executed
app.get("/someauthorisedrouter", function (req, res, next) { ... });
Option 2 Define your middlware function somewhere and require it where needed
/middleware.js
module.exports = function (req, res, next) {
//Do your session checking...
next();
};
Now you can require it wherever you want it.
/index.js
var session_check = require("./middleware"),
router = require("express").Router();
//No need to include the middlware on this function
router.post("/signup", function (req, res, next) {...});
//The session middleware will be invoked before the route logic is executed..
router.get("/someprivatecontent", session_check, function (req, res, next) { ... });
module.exports = router;
Hope that gives you a general idea of how you can achieve this feature.
Express routers have a neat use() function that lets you define middleware for all routes. router.use('/xxxxx', authorize); router.post('/xxxx', 'xxxx'); should work.
Middleware:
sampleMiddleware.js
export const verifyUser = (req, res, next) => {
console.log('Verified')
next();
}
Routes
import express from 'express';
import { verifyUser } from './sampleMiddleware.js';
const userRoutes = express.Router();
userRoutes.route('/update').put(verifyUser, async function(){
//write your function heere
});
You've probably gotten the answer you need but I'll still drop this
router.route('/xxx/xxxx').get(authorize, function(req, res) {...});
I want my logger middleware to log each matched route when response is sent. But there may be any number of nested subroutes. Let's suppose I have this:
var app = express();
var router = express.Router();
app.use(function myLogger(req, res, next)
{
res.send = function()
{
//Here I want to get matched route like this: '/router/smth/:id'
//How can I do this?
});
}
app.use('/router', router);
router.get('/smth/:id', function(req, res, next)
{
res.send(response);
});
Is it possible?
Because app-level middleware has no knowledge of routes, this is impossible. However, if you use your logger middleware as route middleware like:
router.get('/smith/:id', logger, function (req, res) { ... });
You can use a combination of two parameters on the request object:
req.route.path => '/smth/:id'
req.originalUrl => '/router/smth/123'
I'll leave it up to you how you want to combine both into one string.
Here's the code (in express 2.x)
// npm -v express
// 2.14.2
var app = express();
var router = express.Router();
app.use(function(req, res, next) {
var routes = app.routes; // See Reference 1.
for(var method in routes) {
if(routes.hasOwnProperty(method)) {
for(var route in routes[method]) {
if(req.url.toString().match(routes[method][route].regexp)) {
console.log('Route Debugger: ' + routes[method][route].path);
}
}
}
}
next();
});
app.use('/router', router);
router.get('/smth/:id', function(req, res, next)
{
res.send(response);
});
What does this do?
It queries the app.routes object. Now we have access to all the routes defined in our application.
We match the current url req.url with the regular expression of each route.
Since this is a application level middleware, it runs for every request. So you get logging like Route Debugger: /router/smth/:id, if you hit a url like /router/smith/123
Reference 1 : http://thejackalofjavascript.com/list-all-rest-endpoints/
Reference 2 : How to get all registered routes in Express?