According to the documentation, any nodejs express middleware function can be replaced by App or Router instances:
Since router and app implement the middleware interface, you can use
them as you would any other middleware function.
This is some generic error handling I use:
express()
.use('/test', new TestRouter())
.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send(err.message);
})
.listen(PORT);
I tried to replace my error handling with an error-handling Router, but now the callback is never executed and express uses it's default error handling.
const handler = new express.Router();
handler.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send(err.message);
});
express()
.use('/test', new TestRouter())
.use(handler)
.listen(PORT);
Why is this not working as expected and how could I solve it?
Error handlers need to be configured as the last calls to use, as per the docs
You define error-handling middleware last, after other app.use() and routes calls;
I would say "routes" also buckets Routers therefore what you are trying to do doesn't look like it's supported.
Just digging further into this, I believe the issue is down to the fact Routers have separate Layer stacks. Express behind the scenes is effectively just a Router (we see here where this is setup, and then further down where the middleware is delegated on to the Router). Internally, middleware functions are represented as "Layers" (as seen here) and looking at the constructor, we can see Routers have their own stack.
So consider the following example:
express()
.use(new RouterA())
.use(new RouterB())
.use((err, req, res, next) => {
...
})
.listen(PORT);
Which, by looking at the source, can be viewed as:
express()
.use((req, res, next) => {
router.handle(req, res, next);
})
.use((req, res, next) => {
router.handle(req, res, next);
})
.use((err, req, res, next) => {
...
});
Therefore, if an error is thrown in RouterA, the Router would firstly check its own middleware stack for a matching error Layer (i.e. a (err, req, res, next) function) and execute that, it would then bubble up to the app level and perform the same action.
So given your example, if you consider the translated code, this explains why it won't catch your error handler in the second Router - a Router signature does not match that of an error handler therefore it would be skipped.
Related
hi m trying to get an index page but it is showing an error: TypeError: Router.use() requires a middleware function but got a Object, structure: views>attendance>index.ejs how can I resolve this error,
controller:
in controller I write this path:
router.get('/attendance', (req, res) => res.render('attendance/index'));
app.js
require('./models/Attendance');
const attendanceController = require('./controllers/attendanceController');
app.use('/attendance', attendanceController);
The only reason I can imagine for this not working is incorrect exports/imports.
You need to export the router like this in the controller file:
module.exports = router;
Also, by doing router.get('/attendance'... and applying it app.use('/attendance',, the application will listen for requests directed to /attendance/attendance endpoint. I'd change the controller to:
router.get('/', (req, res) => res.render('attendance/index'));
See this for reference: How to write clean, modular express.js applications
I have multiple app.use in my index/starting point of my app.
i.e
app.use(
if (!req.contextToken && req.contextTokenchecked) {
req.queryToFirebase = false;
req.contextTokenchecked = true;
req.contextToken = {}
}
next()
)
app.use(//Do something 2)
and so on..
Now, This is sort of makes my code untidy (in index.js) so I thought about creating a separate js file (say intialize.js) which will contain all my app.use
Till now, I am used to only creating separate routes
const express = require('express')
const router = express.Router()
and then import it in my index.js
app.use('/auth', auth)
But this time I don't want my routes in separate file rather all
app.use()
In one common.js file
Second, I also have a route which loads data from gmail (gmail.js).
app.use('/gmail', gmail)
currently, In all the routes, I am adding a middleware isLoggedInmanually. Is it possible to do something so that all the routes inside it my gmail.js inherits that middleware
The middlewares you register are always executed in the order they are registered. So if you have a code like this:
app.use((req, res, next) => {
// middleware A
next()
})
app.use((req, res, next) => {
// middleware B
next()
})
app.use(middlewareC)
app.use('/gmail', gmail)
Then you can for sure create one common file for those middlewares before the app.use('/gmail', gmail):
common.js
let router = express.Router()
router.use((req, res, next) => {
// middleware A
next()
})
router.use((req, res, next) => {
// middleware B
next()
})
router.use(middlewareC)
module.exports = router
main.js
app.use(require('./common.js'))
app.use('/gmail', gmail)
The API for use (or any others of those registering methods) is ([path,] callback [, callback...])
So you can register as many middlewares as callback as you want, so you can add a isLoggedIn in front of the gmail router:
app.use('/gmail', isLoggedIn, gmail)
If router.all() just match all methods,could it be instead by router.use()?
and what router.use() diff between router.route()?
router.all: What this means is, it doesn't matter the method of the request.. (post, get, put), if the url matches, execute the function.
ex- router.all("/abc",fn) will be work for all request to /abc
router.use() : router.use() helps you write modular routes and modules.. You basically define a middle ware for routes.
router.use("/pqr", pqrRoutes)
now for all requests that start with /pqr like /pqr/new or /pqr/xyz can be handles inside the pqrRoutes.
router.route(): this is nice way to define the different Method implementations for a single url end point.
lets just say you have two api end points. router.get("/jkl") and router.post("/jkl"), with router.route() you cam sort of combine these different api handlers..
you can say router.route("/jkl").get(fn1).post(fn2)
router.all() matches every http protocol, router.use() is for middleware, and router.route() returns an instance of a single route which you can then use to handle HTTP verbs with optional middleware.
You should check out the documentation for more informations
app.all(), which is not derived from any HTTP method. This method is used for loading middleware functions at a path for all request methods.
app.all('/secret', function (req, res, next) {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app.
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
Bascially we use .use when we use a middleware
express.Router
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app.
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', function (req, res) {
res.send('Birds home page')
})
There can we more than 1 router this instance of router has name router defined below the express defination.
Here is the documentation for router
https://expressjs.com/en/guide/routing.html
Router.use()
Routers behave like middleware and can be .use()d by the app in other routers. In other words, routers allow you to chunk your big app into numerous mini-apps that you can later put together. For small apps, this might be overkill, but as soon as you think, “This app.js file is getting big,” it’s time to think about breaking down your app with routers.
router.route(path)
The router.route(path) method is used to chain HTTP verb methods. For example, in a create, read, update, and
delete (CRUD) server that has POST, GET, PUT, and DELETE endpoints for the /posts/:id URL (e.g., /posts/53fb401
dc96c1caa7b78bbdb), we can use the Router class as follows:
var express = require('express');
var router = express.Router();
router.param('postId', function(request, response, next) {
// Find post by ID
// Save post to request
request.post = {
name: 'Node.js',
url: 'http://your-url/node-js-blog'
};
return next();
});
The Router.route(path) method provides the convenience of chaining methods, which is a more appealing way
to structure, your code than re-typing router for each route.
Alternatively, we can use router.VERB(path, [callback...], callback) to define the routes just as we
would use app.VERB(). Similarly, the router.use() and router.param() methods work the same as app.use() and
app.param().
I am creating an express middleware. My index.js exports is a function that returns a function(req,res,next) {...}
function myMiddleware (options) {
//some stuff with options...
return function middleware(req, res, next) {
//stuff
}
}
module.exports = myMiddleware;
So the user would could start using my middleware like this:
var express = require('express'),
myMiddleware = require('my-middleware'),
app = express();
app.use(myMiddleware());
The important thing is that I must make sure that middleware has access to cookies. Of course I could parse req.header.cookie myself but there exists a cookie-parser module that does the parsing for me.
So I would like to make sure that cookie-parser middleware is already being used when my middleware starts up. I could probably instruct the user to first use cookieParser() but I dislike it.
Is there a way to do it easily?
EDIT
I could even port cookie-parser since it is not a huge module. But that is probably the least thing I would do since it can introduce a lot of maintenance work that I would normally not do.
You have two options:
Force the cookie-parser middleware if req.cookies is undefined.
If cookie-parser has already been called, this call will be ignored. See: https://github.com/expressjs/cookie-parser/blob/master/index.js
The downfall to this approach is that the cookieParser middleware will only have the default options.
var cookieParser = require('cookie-parser');
function myMiddleware(options) {
return function(req, res, next) {
return cookieParser()(req, res, function() {
// Your middleware code
return next();
});
}
}
Give a warning if req.cookies is undefined
function myMiddleware(options) {
return function(req, res, next) {
if(!req.cookies) {
// Some warning
}
// Your middleware code
return next();
}
}
In express, the execution order of middleware is defined by the order it has been attached to the app/router.
req.param being an exception, as it is executed before any route handler that matches the parameter.
The order in which your routes and middleware functions are declared is the order which they will be executed. I do not know of a way to change this, maybe fiddling with the internals of express router, but there is no documented/clean way to achive this by default.
To make sure your middleware has access to the cookie parsed by cookie-parser, attach the cookie parsing middleware before any route definitions.
app.use(cookieParser());
// all other middleware that uses cookies
I have created a custom route middle ware for express js.
Example:
var customRouter = function(req, res, next) {
console.log(res);
next();
};
and in app.js
app.use(app.router); //express default router
app.use(customRouter); //my custom router which comes after express default router
My custom router comes after the express default router. What I'm trying to achieve is that to determine if the default express router have already rendered a response or a view.
How do I determine in my route middleware if a view or a response is already rendered in the express route?
As far as I know, when a middleware sends a response, then next() is not called anymore. So your customRouter is not fired in a case, when default router handles a request.
But anyway, you can always check a response if it was already flushed: res.finished => (boolean)