Confusion with app.use with Router() in express - node.js

I was learning Express in Node.js and came across Router() allowing us to modularize our routes. But than I found this code:
// we'll create our routes here
// get an instance of router
var router = express.Router();
...
// route with parameters (http://localhost:8080/hello/:name)
router.get('/hello/:name', function(req, res) {
res.send('hello ' + req.params.name + '!');
});
// apply the routes to our application
app.use('/', router);
What confused me is that why we need to use app.use('/', router); to apply the routes. That is, what if we use app.get('/', router);

I am giving you a simple code example to make you understand the use of express.Router(). Yes you are right that it helps in modularization. Actually it makes our main app.js file clean from all the routes. We just put all those routes based on their purposes in different files and require them when needed.
so suppose I have two files app.js and register.js
// app.js file's code goes here
let express = require("express")
let app = express()
let register = require("./routes/register")
app.use(register) // This will tell your app to import all those routes which are in register
// register.js file's code goes here
let express = require("express")
let router = express.Router()
router.get("/register", callback_function);
router.post("/register", callback_function);
module.exports = router;
So basically what I am trying to show is your register.js can contain all types of HTTP requests(GET, POST, PUT,...) and when we use app.use(register) this will handle all those routes. app.get("route_path", callback_function) is only for handling get requests to that path.

Router is just a middleware of it's own. If you use app.get('/', router) you will use the router just for GET requests. Using use channels all requests there.

When app.use is used then it handled all the HTTP methods, but when app.get is used it takes just GET method.
Added advantage to app.use is that route will match any path that follows its path immediately with a /.
For example:
app.use('/v1', ...)
will match /users, /users/accounts, /users/accounts/account-id, and so on.

Related

Express - can't import routes

I have a following structure,
// app.js
const express = require("express");
const app = express();
app.get("/", require("./routes/index"));
app.get("/users", require("./routes/users"));
app.listen(3000);
// /routes/index.js
const express = require("express");
const router = express.Router();
router.get("/", (req, res) => res.send("index"));
module.exports = router;
// /routes/users.js
const express = require("express");
const router = express.Router();
router.get("/login", (req, res) => res.send("login"));
router.get("/register", (req, res) => res.send("register"));
module.exports = router;
If I use app.use(...) inside app.js then the routes work correctly but I want to use app.get since I want to block any other accessible method.
Right now the index route works fine but other routes does not work.
Working sandbox: https://codesandbox.io/s/cocky-cartwright-h82d2?fontsize=14&hidenavigation=1&theme=dark
The correct way to achieve what you're trying is to utilize the 'use' function.
You said you don't want to use the app.use because you want to block any other accessible method, but utilizing the 'use' function won't allow anything that wasn't declared on your routers, so you don't need to worry about that.
What app.use does is register a middleware function to your app on the specified route. So, the code below:
app.use("/users", require("./routes/users"));
Will make that every request that match the pattern '/users' will utilize the function you provided (in this case, the router inside the users.js file).
So, if someone sends a POST request to /users/register, per example, he will get a 404, because you never created a route to handle a post on that path.
And just to make it clear why the app.get don't work the way you did, let me give a brief explanation.
When you use the app.get function, it'll be expected that the request path matches exactly the one you provided. So, when you do the following:
app.get("/users", require("./routes/users"));
The server will be expecting a request that matches /users exactly. So, something like /users/example will not trigger the callback function.
The thing is, the function to handle the request in the code above is another router:
router.get("/login", (req, res) => res.send("login"));
router.get("/register", (req, res) => res.send("register"));
So, the router will expect that the request path matches /users/login or /users/register exactly. But, if a request path matches /users/register, it will not match /users, so nothing will be called.
The reason why your '/' path works right now is because your router is expecting the same path you used on the app.js file. So, a request to '/' will match both patterns.
you can't use router.get and pass a router
router.get expect to get a method (function).
you should use app.use or use controllers like that
// /controllers/index.js
exports.renderIndex = (req, res) => {
res.send("index")
}
and in app.js
// app.js
const express = require("express");
const app = express();
const indexController = require("./controllers/index");
app.get("/", indexController.renderIndex);
app.listen(3000);

How to set routes in Express? app.use() vs app.get()

I have site stub, where routing is set in 2 places.
First in app.js:
...
var index = require('./routes/index');
var users = require('./routes/users');
...
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/users', users);
...
something is set with use. Next inside referred scripts, like index.js:
var express = require('express');
var router = express.Router();
var fs = require('fs');
var path = require('path');
var config = require('../config');
/* GET home page. */
router.get('/', function(req, res) {
var data = {};
...
Suppose I wish to use infromation from Express Routing doc. Where I should put the routing for, say, /users/:userId/books/:bookId?
In docs, get is called against app, while in my stub, get is called against router and in two-step manner.
Where to hook?
In docs get is called against app because they set their endpoints in app.js file. In your index.js you return the router from the file with module.exports = router;, which is app's router. Now in your app.js file says
app.use('/', index);
app.use('/users', users);
These are the routes. You are saying that all the endpoints which are in index file are starting with / and the endpoints which are in users file are starting with /users.
So the route /users/:userId/books/:bookId must be in users.js file like this
router.get('/:userId/books/:bookId', function(req, res, next) {
// do something
});
If you want to handler this route - /users/:userId/books/:bookId, then you need to write following handler in your routes/users.js file.
router.get('/:userId/books/:bookId', function(req, res) {
var data = {};
});//get route
Basically, in app.js you are categorising url's based on its first part e.g. users. So, all your routes that start with /users will be handled by your routes/users.js class. All other routes will be handled by routes/index.js, because that is defined to handle / (there is no /users, /admin etc. so all routes that are not handled by users.js can be handled in this.)
Also, in these route handler files, you define a router object, add all route handlers to it and export it at the bottom. So when you are in these files, you need to use router and in app.js you can directly use app.get() etc.

Difference between app.use('/', router) and app.use(router)

I am working on a node.js application and saw that some people use
app.use('/',router)
and some people use
app.use(router)
What is the difference between these two and which one should I use?
There's no difference in this case.
app.use([path,] callback [, callback...])
If you call app.use without specifying path explicitly, it takes a default value which is /.
But using this paramaeter you can have more than a single router in your app. See examples in the documentation:
var express = require('express');
var app = express(); // the main app
var admin = express(); // the sub app
admin.get('/', function (req, res) {
console.log(admin.mountpath); // /admin
res.send('Admin Homepage');
});
app.use('/admin', admin); // mount the sub app

Node express routes as modules: where to put `require`s?

Node Express's Routing guide gives the following example for creating routes as modules:
/birds.js:
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')
})
// define the about route
router.get('/about', function (req, res) {
res.send('About birds')
})
module.exports = router
/app.js:
var birds = require('./birds')
// ...
app.use('/birds', birds)
I want to know why they put the first two lines of birds.js there instead of in app.js.
Firstly, app.js calls a method of app. How is app supposed to be defined within app.js? I take it they (oddly) neglected to include that necessary code for the sake of the tutorial.
Secondly, say I wanted a second route as a module, for dogs as well as birds, in a file called dogs.js. Could it look identical to birds.js WRT the first two lines? AFAIK that would result in two instances of express. (Or three if it's needed in app.js as well?!)
The example is not complete. The whole app setup is left out (i asume because it is explained further up in the docs anyway and replaced with // ...). In your app.js you need at least:
var express = require('express');
var app = express();
The first 2 lines in bird.js have nothing to do with the two (missing) lines in app.js. You need them to create a router.
And regarding your last question: Yes, you would create another router exactly like the bird router. A router is not an express app/instance and it's totally fine to have multiple of them in you app.

How can I still use a router in node express and still have a wildcard and params?

So basically I want my code being able to go mywebsite.com/username and itll take them to their profile.
My app.js has -
var user = require('./routes/user');
app.use('/*', user);
and then in my user.js I have
router.get('/:username', function(req, res) {
console.log('the user name', req.params.username);
})
If I change router.get to just router.get('/') my console.log logs out undefined and if I leave it as router.get('/:username') I get a 404.. I also tried doing app.use('/:username', user) as well but that still didn't work.
You should't need to have a wildcard like you do on app.use
Try something like this.
Also see the express router documentation http://expressjs.com/en/guide/routing.html
// Required Moduiles
var express = require('express');
var router = express.Router();
var app = express();
// Add route to get
router.get('/:username', function(req, res) {
res.status(200).send(req.params.username)
})
// Add username
app.use('/', router)
// Start express server
app.listen(3030);
Update -
Just using app.use(router) would do the same thing if all your routes are going to be contained in this new router instance / middleware you are creating in a separate file.

Resources