Let's say I have the following routes:
// routes.js
import PhotoRoutes from './photoRoutes';
const UserBaseRoute = Router();
UserBaseRoute.use('/api/:userId', PhotoRoutes);
// photoRoutes.js
const PhotoRoute = Router();
PhotoRoute.get('/', (req, res) => {
console.log(req.params);
res.end();
});
export default PhotoRoute;
When I hit /api/123/ I expect to use {"userId: 123}' But I don't. Why is the :userId defined in the baseRoute not passed up?
This is a issue related to nested router.
You need to set the mergeParams of child router as true to access params from parent router.
So try following code:
const PhotoRoute = Router({mergeParams: true});
BTW, this option came with Express version 4.5. For more details, refer to the API document
Related
I have the following case:
There is a list of routes in the form
var lst = ["route1/:foo", "route2/:bar", "route3/:bar/route4/:baz", ..] // this list has like 200 entries
I have the following code
app.use(lst, function (req, res) {
// here I want to know which route the middleware was invoked on
// req.route.path doesn't work unless I use app.METHOD()
// req.originalUrl would give me route1/200, instead of route1/:foo
})
What I tried so far:
Using the router stack as in app._router.stack, my routes aren't even registered there - I don't see route1/:foo, route2/:bar and route3/:bar/route4/:baz
Hook into the express router:
var Route = express.Route;
let defaultImplementation = Route.prototype.dispatch;
function foo(req, res) {
console.log('Called route ', req.route.path); // still doesn't trigger on the routes in lst, only parent routes
}
Route.prototype.dispatch = function handle(req, res, next) {
foo(req, res); // req.route is available here
defaultImplementation.call(this, req, res, next);
};
By the way, I'm passing those routes and using them along with http-proxy-middleware https://github.com/chimurai/http-proxy-middleware, so if you have any clues on how do achieve that with that library as well, I'd be very grateful as I couldn't find out.
This is the get request:
this.props.userId contains the userId.
componentDidMount() {
axios.get('/api/auth/booked/' + this.props.userId)
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
}
This is the routes on my backend:
router.get('/booked:id', UserController.bookedClasses);
It's something to do with the '/booked:id'
Result:
GET http://localhost:3000/api/auth/booked/5bdb18071c8fb30d31969aef 404 (Not Found)
Nice and simple but for some odd reason, I can't get a response, I have all my system working apart from this route, can anyone spot anything that shouldn't be there?
Any feedback would be appreciated to help me and others!
This is my routes folder which holds all my routes:
const express = require('express');
const router = express.Router();
const UserController = require('../controllers/auth');
router.post('', UserController.createUser);
router.post('/login', UserController.login);
router.post('/bookclass', UserController.bookClass);
router.get('/:id', UserController.getUser);
router.get('/booked:id', UserController.bookedClasses);
module.exports = router;
Router params must be specified in the path of the route. Example:
'/some/route/:param'
or with multiple params:
'/some/route/:param/:anotherParam'
In your example:
router.get('/booked:id', UserController.bookedClasses);
should be (check the extra / in the path):
router.get('/booked/:id', UserController.bookedClasses);
I am trying to implement routes with classes in my express js application
controller
class User {
constructor (){
this.username = 'me';
}
getUsername(req,res){
res.json({
'name':this.name
});
}
}
export default User;
In my routes
import express from 'express'
import User from './controller'
const router = express.Router();
const user = new User();
router('/',user.getUsername.bind(user));
export default UserRoute
But I got this error
req.next = next;
^
TypeError: Cannot create property 'next' on string '/'
at Function.handle (/var/accubits-workspace/express-es6/node_modules/express/lib/router/index.js:160:12)
you are not using any method on the router object, you need something like get , post, put , delete or other http/https verbs or use for creating middleware.
for example
router.VERB("/", ...);
router.(use HTTP method like(get,post...))('/',user.getUsername.bind(user));
i want to perform some validation and addition to the request on specific parameter for a route and all nested routes.
My REST structure is /room/:room/messages
In my main.js
const roomRoute = require('roomroute.js');
const messageRoute = require('messageroute.js');
app.use('/room',roomRoute);
app.use('/room/:room/messages',messageRoute);
in roomroute.js
const express = require('express');
const router = express.Router();
router.param('room', function (req,res,next,id) {
// Just for demo
var room = {
id: id,
title: 'Testroom'
};
req.room = room;
next();
});
router.get('/:room, function (req,res) {
// Display room to console
console.log(req.room);
res.sendStatus(200).end();
});
module.exports = router;
In messageroute.js
const express = require('express');
const router = express.Router({ mergeParams:true });
router.get('/', function(req,res) {
console.log(req.room); // Not working
});
module.exports = router;
When i do a get to a room eg. /room/1234 then req.room is displayed to the console, which actually is want i want.
But when i do a get to eg. /room/1234/messages the route.param('room'... of the parent is not executed, but instead just the get of the messageroute.js.
Is there a way to achieve that the param is evaluated for the parent route and also for all nested routes ?
Thank you,
Stefan
This looks like a misunderstanding of how nested routers work. In your example you seem to be looking to share a param across roomroute and messageroute, however, both of those routers have no relation to eachother.
Routers become nested when they're supplied as middleware to another router - you have an example of this already....app is a router in itself and you nest both roomroute and messageroute into it. So based on your current setup, if you want to share param('room') across both these routes you will need to configure it at app level i.e.
main.js
const roomRoute = require('roomroute.js');
const messageRoute = require('messageroute.js');
app.param('room', function (req,res,next,id) {
// Just for demo
var room = {
id: id,
title: 'Testroom'
};
req.room = room;
next();
});
app.use('/room', roomRoute);
app.use('/room/:room/messages', messageRoute);
roomroute.js
const router = express.Router({ mergeParams: true });
router.get('/:room', ...);
messageroute.js
const router = express.Router({ mergeParams: true });
router.get('/', ...);
I've made an api and I've routed it as follows:
In the main routes file:
//with sub-route
app.use('/api/test/:test', require('./api/test'));
//Without sub-route
app.use('/api/test2/:test', function(req, res){
console.log('in test', req.params, req.body);
return res.status(200).json({params: req.params, body: req.body});
});
Accessing the second route displays the :test in req.params, as expected.
In the modular routes folder ('./api/test') I have a sub-router (index.js) which looks like this:
router.get('/:test2', controller.getItem);
with a handler:
exports.getItem = function getItem(req, res) {
console.log('in getItem \nreq.params', req.params, '\nreq.body: ', req.body);
return res.status(200).json({yes: 'yes', params: req.params, body: req.body});
};
So the first url, which has no sub-routing is: /api/test2/:test and logs out whatever you put in place of :test in req.params.
The second url, which has sub-routing is: /api/test/:test/:test2, but when you send your get request only :test2 appears in req.params.
It seems that if you use this pattern any variables in the 'root' of the route (ie in the primary router) are not picked up.
Is there a way to fix this?
Thanks
You will need a middleware to fix this for you:
function paramFix(req, res, next) {
req._params = req.params;
next();
}
app.use('/api/test/:test', paramFix, require('./api/test'));
And then use req._params.test in your last callback function.
So reflect multiple levels of mounting you can extend your middleware like this:
function paramFix(req, res, next) {
req._params = req._params || {};
for (var key in req.params) {
if (req.params.hasOwnProperty(key)) {
req._params[key] = req.params[key];
}
}
next();
}
app.use('/api/test/:test', paramFix, require('./api/test'));
express.js (>= v4.5.0+) provides a direct solution without having to implement middleware.
https://expressjs.com/en/api.html#express.router
While creating the router, pass the mergeParams flag.
var router = express.Router({ mergeParams: true })
mergeParams preserves the req.params values from the parent router. If the parent and the child have conflicting param names, the child’s value takes precedence.