I'm not sure if this is a bug in Express, or if I'm just doing something wrong (probably the latter), but I'm finding that req.params is only retaining parameters in the final step of the request. To demonstrate what I mean:
Working Example:
router.get('/:id/test', function(req, res){
// req.params.id is not undefined
});
Doesn't Work :(
File 1:
router.use('/:id', require('./file2'));
File 2:
router.get('/test', function(req, res){
// req.params.id is undefined?!
});
Now... the above seems totally illogical to me, seeing as the Express generator defines routes in the above way - and it must still be defined in the path somewhere. Surely I should still be able to access "id"?
So basically, am I missing something? Is this deliberate/is it documented? FWIW I'm using Express v4.12.0.
Disclaimer: the file thing is probably irrelevant, but better to be safe than sorry.
When you create your Router in File 2, you need to tell it to inherit params from parents.
var router = express.Router({mergeParams: true});
http://expressjs.com/api.html#router
Related
I´ve setup a little NodeJS API with 'expressjs'. In my code I have some similar code blocks looking like this:
app.get('/api/my/path', (req, res) => {
doSomethingUseful();
});
All thoses requests do something different, so the function being called is always different too.
I´m asking myself if this is good practice for writing code in NodeJS or not.
If there is a better / cleaner way of writing all those paths I would appreciate if you could tell me how or at least giving me a place to look for it.
EDIT 1: To be clear: I ask if it´s a good idea to write a lot of 'app.get(...)' into one source code file or if there is a better way?
Yes there is a better way than writing all routes in one file. For example, let us say you have routes for users and questions.
For users, you want get/set/put/delete for profile, and similarly for questions.So you create the following folder structure: /api/users and /api/questions
In /api/users,
const express=require('express')
const router=express.Router()
//this handles route: /users
router.get('/',(req,res)=>{})
//this handles route: /users/profile
router.get('/profile',(req,res){})
//this is to retrieve profile of specific user by user id :/users/profile/:userID
router.get('/profile/:userId',(req,res))
router.post('/profile',(req,res))
.
.
Then, in your index.js or entry point of your project,
const users=require('./api/users')
const questions=require('./api/questions')
app=require('express')
app.use('/users',users)
app.use('/questions',questions)
So in effect, you say for any /users route, refer to the users.js file, for any /questions routes, refer questions.js file and so on
Use a simple module, don't be invoking routes until you form a heap.
Try Route Magic
You want to do just 2 lines of code and have the module read your directory and file structure to handle all the app.use routing invocations, like this:
const magic = require('express-routemagic')
magic.use(app, __dirname, '[your route directory]')
For those you want to handle manually, just don't use pass the directory to Magic.
Currently working on a nodejs express server. And I think I'm doing something in an inefficient way. I have this route set up
app.get('/admin/scanTable/:table', require('./AUTH/ValidateCookie.js'), require('./AUTH/verifyURI.js'), require('./ROUTES/render.js'));
so the url here is /admin/scanTable/:table. I know I can get the whole path with req.route.path. I know I can use req.params.table to collect the table parameter. But the thing I don't know how to get is the first part of the path, in this case admin. I know I could get it by looking for / symbols and slicing the parts I need from req.route.path but I figure with all these functionalities that express has, there's probably a better way of doing this.
I know I can use
app.use('/admin', function(req, res, next){console.log('admin called'), next();});
to check if this part of the uri was called to then execute some code, but it's not really what I want. Can anyone tell me the easiest way to find this? At the moment I have attached a variable to req.string whenever app.use('/admin' is called it will attach the string admin to this variable which then makes it available to all other functions that are called. But even this feels like overkill. Any Ideas?
Both options you describe are valid and straightforward:
Using a regex on req.route.path, a la /^admin/.test(req.route.path)
Using middleware to attach a new property to the req object, a la
app.use('/admin', function(req, res, next){ req.adminRoute = true; next();});
or if you need to do this same thing for all admin routes, do it once:
var adminRouter = require("express").Router();
router.get("/scanTable/:table", require("./AUTH/ValidateCookie.js"), ...);
router.use(function (req, res, next) { req.adminRoute = true; next(); }));
app.use("/admin", adminRouter);
I don't know the context of your application, but I would consider using the last example, and putting anything else that's specific to /admin routes as middleware also.
I am building simple app to teach myself node and I've got this problem.
Console.log is not executed at all. Do you have any idea why?
I have 404 error but nothing else. App doesnt crash, I just cant get this view.
router.get('/charts/top/:exercise', function(req, res, next) {
console.log("exercise: " + req.params.exercise);
res.render("top", {});
});
SOLUTION: Since this was in separate routes folder in charts.js file, there should not be /charts but just /top/:exercise
Assuming your router comes from :
var express = require('express');
var router = express.Router();
You will need to export this module for your server to know that these routes are handled. with the following :
module.exports = router;
Under all your routes definitions.
Now, your app just needs to call this said file with the routes to be handled.
var handler = require('./handler');
-Some code-
app.use('/', handler);
.use will set the primary pivot of the route to your router. It gives the ball to it. In this exemple, everything from / will be passed to router. If you really want to make this clean, change your router variable in your file to charts and use it in your app to everything that starts with /charts
Then in your charts file you will be able to handle /top/:exercice
You can make multiple levels of routing like this with .use to set your new point of handling.
Also, I would like to point out that you don't need "next" in your function because you do not have any callback.
Edit : And remember, if 2 routes could be handled, it will always be the first one declared to catch it. That way, declare some routes with a if else logic behind it. Giving the more specific choice first.
I'm not sure if this is a bug in Express, or if I'm just doing something wrong (probably the latter), but I'm finding that req.params is only retaining parameters in the final step of the request. To demonstrate what I mean:
Working Example:
router.get('/:id/test', function(req, res){
// req.params.id is not undefined
});
Doesn't Work :(
File 1:
router.use('/:id', require('./file2'));
File 2:
router.get('/test', function(req, res){
// req.params.id is undefined?!
});
Now... the above seems totally illogical to me, seeing as the Express generator defines routes in the above way - and it must still be defined in the path somewhere. Surely I should still be able to access "id"?
So basically, am I missing something? Is this deliberate/is it documented? FWIW I'm using Express v4.12.0.
Disclaimer: the file thing is probably irrelevant, but better to be safe than sorry.
When you create your Router in File 2, you need to tell it to inherit params from parents.
var router = express.Router({mergeParams: true});
http://expressjs.com/api.html#router
In express, when I use routing middleware, is it OK to append to the request object? Or is it a bad pattern? Alternatives? Thanks.
app.get('/', getLayout, function(req, res){
if(req.layout == 'simple') ...render simple layout...
else ...render full layout...
});
where
getLayout = function(req, res, next){
req.layout = (req.params.blah == 'blah') ? 'layout_simple' : 'layout_full';
next();
}
I don't see why you shouldn't.
I do it a lot.
I am under the impression this is what middleware typically does.
From the express docs:
http://expressjs.com/guide.html#route-middleware
They set req.user in their middleware as the current user.
I agree with j_mcnally that this is a fine pattern as long as you don't go overboard. Specifically, I append most things that are more closely related to the response to the res object. This would be things like layout info, HTML fragments, my intermediate jsdom env representation of the response, etc. For req, tacking on things that are representations of query string or request body info makes sense. This would be things like input parameters, parsed search queries, the current user object, etc.
The express docs suggest it's somewhat a standard practice:
http://expressjs.com/guide.html#route-middleware
But it can significantly effect performance because of the way V8 works:
http://blog.tojicode.com/2012/03/javascript-memory-optimization-and.html
http://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript