Express JS Router Middleware Abstraction - node.js

I have developed an API using Node.js + Express JS and i use token-based authentication.
I used two differents routers in this api, userRoute (/USER) and postRoute (/POST). The postRoute can be used within authentication but userRoute needs the token.
To solve that i use a router middleware for userRoute but it interferes with portRoute
This is the code:
...
var postRoute = express.Router();
var userRoute = express.Router();
// Route middleware to verify a token
userRoute.use(function(req, res, next) {
security.checkToken(req,res, next);
});
userRoute.route('/users')
.get(userCtrl.findAllUsers)
.post(userCtrl.addUser);
postRoute.route('/posts')
.get(userCtrl.findAllPosts)
.post(userCtrl.addPost);
app.use(userRoute);
app.use(postRoute);
...
If i try to access '/posts' the servers checks the token and does not let me in. I know if i change the order of app.use it works, but i dont understand why works in this way if i am using "Router Middleware".
Someone knows?

This happens because if the express router implementation, you will be able to understand it quite easily if you have a look at it. Here is the path: node_modules/express/lib/router/index.js. Every time that you call the Router(), like in your case
var postRoute = express.Router();
var userRoute = express.Router();
this function will be invoked:
var proto = module.exports = function(options) { ... }
and it is true that there is a different router instance that is being returned every time. The difference is in the way that the use is registering the middlewares. As you see the use it is registered against the proto.use
proto.use = function use(fn) { ... }
this means that the middleware that you register there they will be registered for every instance of the router that you define.

Related

how do we differentiate a private and public API in node js

example: public api doesn't require authentication, private route should pass through middleware authentication. But how do we differentiate incoming http request is public or private.
If you're using Express, there are many choices. A simple design choice woudl be to put your private APIs on a router that has middleware that checks for authentication before routing to any of the routes and put the public APIs on a router that does not have the middleware check. Then, the router mechanics built into Express and a properly placed middleware on the router that requires auth would do all the work for you.
Here's a simple example:
const express = require('express');
const app = express();
const routerAuth = express.Router();
const routerPublic = express.Router();
// check auth here in the routerAuth router as the first route definition in that router
routerAuth.use((req, res, next) => {
// check auth here
if ( /* code here to check authorization */) {
next();
} else {
// not authorized
res.status(401).send("Not authorized");
// or maybe just res.redirect("/login");
}
});
// routers on routerAuth
routerAuth.get("/seeEverything", ...)
routerAuth.get("/admin", ...)
// routes on routerPublic
routerPublic.get("/", ...);
routerPublic.get("/login", ...);
routerPublic.get("/signup", ...);
// hook the routers into our server
// specify the public router first so they get a chance to be matched
// before routerAuth enforces authentication
app.use(routerPublic);
app.use(routerAuth);
app.listen(80);
It would be common to put each of these routers in their own module and then import them, but I've skipped that part for simplicity's sake here. This example shows each router sharing the same path namespace, but you could also put the private router on its own path prefix if you want.

express.Router() vs express() in express

As mentioned in express routing guide and this answer, we can create "mini-app" and use it from the main app. However I saw a code where it uses app instead of router in the module
app.js
var express = require('express');
var userRoutes = require('./routes/user');
var app = express();
app.use('/user', userRoutes);
module.exports = app;
routes/user.js
var express = require('express');
var app = express(); // not express.Router() !!
app.get('/:name', function(req, res) {
var userName = req.params.name;
res.render('user.jade', {
userName: userName
});
});
module.exports = app;
I assumed the correct usage in routes/user.js should be
router = express.Router()
instead of
app = express()
but app = express() also works! what are the differences and why router = express.Router() is better?
When you are working with a server where there are many routes, it can be confusing to leave them in a Main file together. The let router = express.Router() option works differently than let app = express().
While the app returns an app object, router will return a small app fragment, similar to the app, where you will use logic to call them later on the Main.
The most important, about your question, is that a router, which is isolated, will not interfere with others in the application, being a single environment.
https://expressjs.com/en/api.html#router
A router object is an isolated instance of middleware and routes. You can think of it as a “mini-application,” capable only of performing middleware and routing functions. Every Express application has a built-in app router.
A router behaves like middleware itself, so you can use it as an argument to app.use() or as the argument to another router’s use() method.

Difference between app.get() or router.get() - ExpressJs

What is the difference between:
var express = new express();
var app = new express();
app.get("/", function() {
.....
})
And:
var express = new express();
var router= express.Router();
router.get("/", function() {
.....
})
app.get can be used to create routes for your application at the top level.
From the documentation about 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”.
A router needs to be mounted to an app:
const router = express.Router();
router.get("/", (res, req) => res.end());
router.post("/", (res, req) => res.end());
app.use("/empty", router);
This allows you to more easily encapsulate the functionality of several routes into an app which will be namespaced under a particular route.
When express() is called in app.js, an app object is returned. Think of an app object as an Express application.
When express.Router() is called, a slightly different "mini app" is
returned. The idea behind the "mini app" is that different routes in
your app can become quite complicated, and you'd benefit from moving
that logic into a separate file.
Check this SO Thread for details.

Creating a Modular REST API in ExpressJS

I'm having some trouble creating a RESTful API in Node/Express. In the app I'm building, a user has many messages, and messages belong to users. I need to be able to make an HTTP requests to retrieve all messages by a particular user. Here's the basic structure of the app, starting with the basic server, which delegates routing to a file called 'config/middleware.js'.
//server.js
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
require('./config/middleware.js')(app, express);
var port = process.env.PORT || 8080;
app.use(bodyParser.json());
app.use(express.static(__dirname + '/../client'));
app.listen(port);
This is the middleware file where we send requests to the appropriate router. A request made to 'users/5/messages' would get routed to the messages router, and a request made to 'users/5' would get routed to the users router.
// config/middleware.js
module.exports = function(app, express) {
var usersRouter = express.Router();
var messagesRouter = express.Router();
app.use('/users/:userId/messages', messagesRouter);
app.use('/users', usersRouter);
require('../routers/users')(usersRouter);
require('../routers/messages')(messagesRouter);
};
This is the messages router. If a get request is made to '/users/5/messages', I want the getAllMessages function to be run, which should return all messages by the user with userId 5.
// routers/messages.js
var messagesController = require('../controllers/messages');
module.exports = function(app) {
app.get('/:messageId', messagesController.getMessage);
app.get('/', messagesController.getAllMessages);
};
The problem is that the getAllMessages function doesn't have access to the 'userId' parameter (with value of 5), which is required in order to make an appropriate query to the database. The getAllMessages function in the controller expects the userId to be stored on req.params.userId. Is there any way to get the userId of 5 to be present on the req.params object inside the getAllMessages function?
The req.params are not passed down the route chain. To do so, you could do something like
In server.js, create a key on req. This will pass on your data between routes. Do this before mounting the routes.
app.use(function (req, res, next) {
req._data = {};
next();
});
In config/middleware.js,
module.exports = function(app, express) {
var usersRouter = express.Router();
var messagesRouter = express.Router();
// attach usedId
app.use('/users/:userId/messages', function (req, res, next) {
req._data.userId = req.params.userId;
next();
});
// mount the router
app.use('/users/:userId/messages', messagesRouter);
app.use('/users', usersRouter);
require('../routers/users')(usersRouter);
require('../routers/messages')(messagesRouter);
};
This way, you would have access to req._data.userId in routers/messages.js.
Side note: A better way to structure the routes would be to use something like, (read shameless plug), https://github.com/swarajgiri/express-bootstrap/blob/master/web/routes.js
You can use app.locals or res.locals to pass some datas.
There is a good explanation about locals.
An usage sample:
app.locals.userid = req.params.userId; //binding userid
app.locals.userid // => '5'
OR: put a global variable.
user_id_tmp = req.params.userId;
Now this is become global variable in app. So you can call user_id_tmp variable from anywhere.
I was looking for same.
Here is modules app example on github and auther site
Also we can change or update structure base on our requirements

Express router param - chaining with URL

I have a full CRUD API defined in Express, and I'd like to remove the duplication of base and use the snazzy route function, but I fear it's not possible.
Current:
var router = express.Router();
var base = '/api/foo/bar/';
router.get(base, this.list);
router.get(base + ':id', this.read);
router.post(base, this.create);
router.put(base + :id', this.update);
router.del(base + :id', this.del);
Desired:
var router = express.Router();
router.route('/api/foo/bar')
.get(this.list)
.get(':id', this.read)
.post(this.create)
.put(':id', this.update)
.del(':id', this.del)
The problem is that the verb functions (get, post, put, del) do not accept a string as their first parameter.
Is there a similar way to achieve this?
Important: Using this technique will work, but we aware that as of Express 4.3.2, all subroutes defined on the nested router will not have access to req.params defined outside of it, nor param middleware. It's completely quarantined. This, however, is subject to change in a later 4X version. See https://github.com/visionmedia/express/issues/2151 for more (up to date) info.
How about this instead:
// api.js
var router = express.Router();
router
.route('/')
.get(this.list)
.post(this.create);
router
.route('/:id')
.get(this.read)
.put(this.update)
.del(this.del);
module.exports = router;
// app.js / main.js
app.use('/api/foo/bar', require('./api'));
or if you want to chain all of them at once:
// api.js
var router = express.Router();
router
.get('/', this.list)
.get('/:id', this.read)
.post('/', this.create)
.put('/:id', this.update)
.del('/:id', this.del);
module.exports = router;
// app.js / main.js
app.use('/api/foo/bar', require('./api'));

Resources