app.js:
var app = express();
app.use('/my-page', require('./routes/my-page.js'));
my-page.js:
const router = require('express').Router();
router.get('/one', function (req, res, next) {
return res.send('this is /my-page/one');
});
router.get('/my-other-page', function (req, res, next) {
return res.send('this is /my-other-page');
});
How do I make it so my-other-page isn't under my-page, but is instead on the root? I do not want to change app.js because i still want most routes under that page, just one specific one that I want to not have /my-page.
I tried .. in the route but doesnt work. I tried making app from app.js global, but that didn't seem to work either.
Typically you have a routes.js that can import the other routes. (You don't need to, but I think it will better for your structure).
app.js
var app = express();
app.use('/', require('./routes/routes.js'));
routes.js
const router = require('express').Router();
router.use('/my-page', require('./my-page.js'));
router.use('/my-other-page', require('./my-other-page.js'));
Then you split my-page.js and my-other-page.js.
my-page.js
const router = require('express').Router();
// This is /my-page/one
router.get('/one', function (req, res, next) {
return res.send('this is /my-page/one');
});
my-other-page.js
// This is /my-other-page/one
router.get('/one', function (req, res, next) {
return res.send('this is /my-other-page/one');
});
I have checked many answers in other pages and forums, but I still don't get it. What did I do wrong? Help me
*edited. I have added requiring routes and app.use. It looks like function isLOggedIn is not exporting but I don't know how to do that. I did like this in another app, it worked there.
auth-routes.js
const express = require("express"),
router = express.Router(),
passport = require("passport")
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect("/auth/login")
}
module.exports = router
user-routes.js
const express = require("express"),
router = express.Router(),
authRoutes = require("./auth-routes")
router.get("/profile", authRoutes.isLoggedIn, (req, res) => {
res.render("user/profile", {user: req.user})
})
module.exports = router
requring routes
const titleRoutes = require("./routes/title-routes")
const authRoutes = require("./routes/auth-routes")
const userRoutes = require("./routes/user-routes")
app.use
app.use(titleRoutes)
app.use("/auth", authRoutes)
app.use("/user", userRoutes)
In auth-routes.js you don't export isLoggedIn. So in user-routes.js, authRoutes.isLoggedIn is undefined.
You can change:
module.exports = router
into:
exports.isLoggedIn = isLoggedIn
or using module.exports into:
module.exports = { isLoggedIn: isLoggedIn }
A useful link to understand export in nodejs https://www.sitepoint.com/understanding-module-exports-exports-node-js/
so I have a route written with app.route:
app.route('/word/:id')
.get(word.getWord)
.put(word.updateWord)
.delete(word.deleteWord);
Now I want to re-write the route with some middleware. I know how to do this route by route, for example the first route would be:
app.get('/word/:id', connect.ensureLoggedIn('/auth/facebook'), word.getWord);
But can I apply the same middleware to all 3 routes at once?
you can use something like
var express = require('express');
var router = express.Router();
// -- #section router middleware
router.use(function (req, res, next) {
/* your code here */
next();
});
// -- #section routes
router.get('/users', function (req, res) {
//res.render('users')
});
router.post('/users', function (req, res) {
});
I need to load some async config before run my app, something like this:
var express = require('express');
var router = express.Router();
var myModule = require("myModule");
myModule.create().generateModel().then(tagger => {
router.post('/tag', function(req, res, next) {
res.json(tagger.tag(req.body.text));
});
module.exports = router;
});
but this does not work because require is sync. How can I make this work? How can I reutilize "tagger" in other modules?
You don't need to set module.exports asynchronously because you're exporting the router which is already defined synchronously:
var express = require('express');
var router = express.Router();
var myModule = require("myModule");
myModule.create().generateModel().then(tagger => {
router.post('/tag', function(req, res, next) {
res.json(tagger.tag(req.body.text));
});
});
module.exports = router;
Suppose I want to have REST endpoints which look roughly like this:
/user/
/user/user_id
/user/user_id/items/
/user/user_id/items/item_id
CRUD on each if makes sense. For example, /user POST creates a new user, GET fetches all users. /user/user_id GET fetches just that one user.
Items are user specific so I put them under user_id, which is a particular user.
Now to make Express routing modular I made a few router instances. There is a router for user, and a router for the item.
var userRouter = require('express').Router();
userRouter.route('/')
.get(function() {})
.post(function() {})
userRouter.route('/:user_id')
.get(function() {})
var itemRouter = require('express').Router();
itemRouter.route('/')
.get(function() {})
.post(function() {})
itemRouter.route('/:item_id')
.get(function() {})
app.use('/users', userRouter);
// Now how to add the next router?
// app.use('/users/', itemRouter);
URL to item is descendents of the URL hierarchy of the user. Now how do I get URL with /users whatever to userRouter but the more specific route of /user/*user_id*/items/ to the itemRouter? And also, I would like user_id to be accessible to itemRouter as well, if possible.
You can nest routers by attaching them as middleware on an other router, with or without params.
You must pass {mergeParams: true} to the child router if you want to access the params from the parent router.
mergeParams was introduced in Express 4.5.0 (Jul 5 2014)
In this example the itemRouter gets attached to the userRouter on the /:userId/items route
This will result in following possible routes:
GET /user -> hello user
GET /user/5 -> hello user 5
GET /user/5/items -> hello items from user 5
GET /user/5/items/6 -> hello item 6 from user 5
var express = require('express');
var app = express();
var userRouter = express.Router();
// you need to set mergeParams: true on the router,
// if you want to access params from the parent router
var itemRouter = express.Router({mergeParams: true});
// you can nest routers by attaching them as middleware:
userRouter.use('/:userId/items', itemRouter);
userRouter.route('/')
.get(function (req, res) {
res.status(200)
.send('hello users');
});
userRouter.route('/:userId')
.get(function (req, res) {
res.status(200)
.send('hello user ' + req.params.userId);
});
itemRouter.route('/')
.get(function (req, res) {
res.status(200)
.send('hello items from user ' + req.params.userId);
});
itemRouter.route('/:itemId')
.get(function (req, res) {
res.status(200)
.send('hello item ' + req.params.itemId + ' from user ' + req.params.userId);
});
app.use('/user', userRouter);
app.listen(3003);
manageable nested routes...
I wanted a specific example of doing nested routes in a very manageable way in express 4 and this was the top search result for "nested routes in express". Here's an API that would have many routes that would need to be broken up for example.
./index.js:
var app = require('express')();
// anything beginning with "/api" will go into this
app.use('/api', require('./routes/api'));
app.listen(3000);
./routes/api/index.js:
var router = require('express').Router();
// split up route handling
router.use('/products', require('./products'));
router.use('/categories', require('./categories'));
// etc.
module.exports = router;
./routes/api/products.js:
var router = require('express').Router();
// api/products
router.get('/', function(req, res) {
res.json({ products: [] });
});
// api/products/:id
router.get('/:id', function(req, res) {
res.json({ id: req.params.id });
});
module.exports = router;
Nesting example in folder structure
I noticed some comments on "nesting folder structure". It is implied in this however not obvious so I added the section below. Here's a specific example of a nested folder structure for routes.
index.js
/api
index.js
/admin
index.js
/users
index.js
list.js
/permissions
index.js
list.js
This is more a general example of how node works. If you use "index.js" in folders similarly to how "index.html" works in web pages for a directory default, this will be easy to scale your organization based off of recursion without changing your entry points to code. "index.js" is the default document accessed when using require in a directory.
contents of index.js
const express = require('express');
const router = express.Router();
router.use('/api', require('./api'));
module.exports = router;
contents of /api/index.js
const express = require('express');
const router = express.Router();
router.use('/admin', require('./admin'));
module.exports = router;
contents of /api/admin/index.js
const express = require('express');
const router = express.Router();
router.use('/users', require('./users'));
router.use('/permissions', require('./permissions'));
module.exports = router;
contents of /api/admin/users/index.js
const express = require('express');
const router = express.Router();
router.get('/', require('./list'));
module.exports = router;
There is some DRY issues here possibly but it does lend itself well to encapsulation of concerns.
FYI, recently I got into actionhero and have found it to be full featured w/sockets and tasks, more like a true framework all-in-one flipping the REST paradigm on its head. You should probably check it out over going naked w/ express.
var userRouter = require('express').Router();
var itemRouter = require('express').Router({ mergeParams: true });
userRouter.route('/')
.get(function(req, res) {})
.post(function(req, res) {})
userRouter.route('/:user_id')
.get(function() {})
itemRouter.route('/')
.get(function(req, res) {})
.post(function(req, res) {})
itemRouter.route('/:item_id')
.get(function(req, res) {
return res.send(req.params);
});
app.use('/user/', userRouter);
app.use('/user/:user_id/item', itemRouter);
The key to the second part of your question is the use of the mergeParams option
var itemRouter = require('express').Router({ mergeParams: true });
From /user/jordan/item/cat I get a reponse:
{"user_id":"jordan","item_id":"cat"}
Using #Jason Sebring solution, and adapting for Typescript.
server.ts
import Routes from './api/routes';
app.use('/api/', Routes);
/api/routes/index.ts
import { Router } from 'express';
import HomeRoutes from './home';
const router = Router();
router.use('/', HomeRoutes);
// add other routes...
export default router;
/api/routes/home.ts
import { Request, Response, Router } from 'express';
const router = Router();
router.get('/', (req: Request, res: Response) => {
res.json({
message: 'Welcome to API',
});
});
export default router;
In the spirit of Express modular routers, we should have a separate router for users and for items. That router isn't part of our top-level application logic. We can nest it in our users' router instead.
Users router
const users = require('express').Router();
const items = require('./items');
//...
// Our root route to /users
albums.get('/', function(req, res, next) {
// res.send() our response here
});
// A route to handle requests to any individual user, identified by an user id
users.get('/:userId', function(req, res, next) {
let userId = req.params.userId;
// retrieve user from database using userId
// res.send() response with user data
});
// Note, this route represents /users/:userId/items because our top-level router is already forwarding /users to our Users router!
users.use('/:userId/items', items);
//...
module.exports = users;
Items router
// We need to merge params to make userId available in our Items router
const items = require('express').Router({ mergeParams: true });
//...
// The root router for requests to our items path
items.get('/', function(req, res, next) {
let userId = req.params.userId; // Here is where mergeParams makes its magic
// retrieve user's track data and render items list page
});
// The route for handling a request to a specific item
items.get('/:itemId', function(req, res, next) {
let userId = req.params.userId; // <-- mergeParams magic
let itemId = req.params.itemId;
// retrieve individual item data and render on single item page
});
//...
module.exports = items;
Source
try to add { mergeParams: true } look to simple example which it middleware use it in controller file getUser at the same for postUser
const userRouter = require("express").Router({ mergeParams: true });
export default ()=>{
userRouter
.route("/")
.get(getUser)
.post(postUser);
userRouter.route("/:user_id").get(function () {});
}
Express router(express.Router()) keeps params seprate so you would explicitly have to tell express to merge these params.
eg:
express.Router({ mergeParams: true })
//above line is answer to your question.
You need only one router, and use it like this:
router.get('/users');
router.get('/users/:user_id');
router.get('/users/:user_id/items');
router.get('/users/:user_id/items/:item_id');
app.use('api/v1', router);