Express 4 route handling with named parameters and router.param() - node.js

Is there a clean way to handle key/value query params in Express 4 routes?
router.route('/some/route?category=:myCategory')
I want to detect the presence of 'myCategory' in this route and use router.param([name], callback) to handle the associated logic.
router.param('myCategory', function(req, res, next, id) {
/* some logic here... */
});
The above 'router.param()' works fine if I have a route like /some/route/:myCategory but fails if I use
router.route('/some/route?category=:myCategory')
Am I doing something wrong here, or is this not supported in the Express 4 router out of the box?

Express treats properties after a ? as query params. So for:
/some/route?mycategory=mine
you would have to use:
req.query.mycategory or req.query['mycategory']
See this for more examples.

Related

Function isn't being called in Node Js using REST API

I am writing a code in Node JS, which uses mustache for templating html and REST API as backend.
Here is my code that doesn't work.
function setupRoutes(app) {
const base = app.locals.base;
app.get(`${base}/search.html`,doSearchContent(app));
app.get(`${base}/:name`,doGetContent(app));
}
function doSearchContent(app) {
return async function(req, res) {
console.log("here");
}; };
When I run my program and go to base/search.html. It never calls the doSearchContent method.
Any idea why and how I can fix this?
EDIT: The doGetContent works as expected. It's when I run the search.html it doesn't
The express paths should be started with a leading slash. Please change your routes addition to something like this:
...
app.get(`/${base}/search.html`,doSearchContent(app));
app.get(`/${base}/:name`,doGetContent(app));
...
Express matches the path of http request against the 'path' provided for all routes to decide which routes must be called. Since the http paths always start with a slash, your routes also must specify those to match.
These lines
app.get(`${base}/search.html`,doSearchContent(app));
app.get(`${base}/:name`,doGetContent(app));
are not working as you expect. In Express routes we don't invoke functions directly. Instead, we either pass a name of a callback fucntion to invoke, that receives req and res params, or an anonymous callback. In your case it could be something like this:
app.get(`${base}/search.html`,(req, res) => {
console.log("It's alive!");
doSearchContent(app);
});
app.get(`${base}/:name`, (req, res) => {
doGetContent(app)
});
The express paths should be started with a leading slash.
This is not true
Have you added search.html file or used a template to build the HTML?
Make sure the template is being called and not the html file.
Other than that your code looks fine and it should work

how to extract part of url server side in nodejs express

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.

Express Router Middleware acts on unintended routes

I'm trying to use Express Middleware to validate that users are authorized for some of my requests. But, some requests do not require any validation. In a router, I have something like this:
// Routes that end in /transactions
module.exports = function(router, isAuthenticated, acl) {
router.post('/transactions', isAuthenticated, acl.isAdminOrFrom, TransactionHandler.transactions.post);
// Get most recent transactios by general, category, or userId
router.get('/transactions/:timeStamp', isAuthenticated, TransactionHandler.transactions.findMostRecent);
router.get('/transactions/categories/:category/:timeStamp', isAuthenticated, TransactionHandler.transactions.category.findMostRecent);
router.get('/transactions/users/:user_id/:filter/public/:timeStamp', isAuthenticated, TransactionHandler.transactions.userId.findMostRecent);
// Get the total reps traded on Repcoin so far
router.get('/transactions/totaltraded', TransactionHandler.transactions.total.get);
Notice that the last route I've listed does not have isAuthenticated there. But, putting that middleware in the above routes has made it act in the last one as well. I also tried something like this:
router.use('/transactions/:timeStamp', TransactionHandler.transactions.findMostRecent);
router.get('/transactions/:timeStamp', TransactionHandler.transactions.findMostRecent);
But the middleware still seems to execute on anything that calls router.get(). How can I use my middleware on a per-route basis?
I think this could be because router.post('/transactions', ... matches before router.get('/transactions/totaltraded', .... You could try to change the ordering so that the latter route definition is before former and see if it makes any difference. Also try to debug which handlers it triggers on a given route.

Express route parsing

I'm trying to create a route for the following URL:
http://localhost:5000/api/querystring?parameter1=value1&parameter2=value2
My route looks like this:
app.get('/api/:querystring/:parameter1?/:parameter2?', function(req, res) {
// do stuff
})
How can I create a route that matches the given URL?
You can't include query string parts in the route ... you will have to leave them off.
app.get('/api/querystring' ...
Then in the callback you can look at req.query to see the parameters. If you were to compare to the query, the order of the query string parameters would matter. It shouldn't.
If you want /api/querystring?parameter1=foo and /api/querystring?parameter2=bar to use different routes, you will have to handle this by calling separate functions within the app.get route callback above.

Express Framework app.post and app.get

I am fairly new to the express framework. I couldn't find the documentation for application.post() method in the express API reference. Can someone provide a few examples of all the possible parameters I can put in the function? I've read a couple sites with the following example, what does the first parameter mean?
I know the second parameter is the callback function, but what exactly do we put in the first parameter?
app.post('/', function(req, res){
Also, let's say we want the users to post(send data to our server) ID numbers with a certain format([{id:134123, url:www.qwer.com},{id:131211,url:www.asdf.com}]). We then want to extract the ID's and retrieves the data with those ID's from somewhere in our server. How would we write the app.post method that allows us to manipulate the input of an array of objects, so that we only use those object's ID(key) to retrieve the necessary info regardless of other keys in the objects. Given the description of the task, do we have to use app.get() method? If so, how would we write the app.get() function?
Thanks a lot for your inputs.
1. app.get('/', function(req, res){
This is telling express to listen for requests to / and run the function when it sees one.
The first argument is a pattern to match. Sometimes a literal URL fragment like '/' or '/privacy', you can also do substitutions as shown below. You can also match regexes if necessary as described here.
All the internal parts of Express follow the function(req, res, next) pattern. An incoming request starts at the top of the middleware chain (e.g. bodyParser) and gets passed along until something sends a response, or express gets to the end of the chain and 404's.
You usually put your app.router at the bottom of the chain. Once Express gets there it starts matching the request against all the app.get('path'..., app.post('path'... etc, in the order which they were set up.
Variable substitution:
// this would match:
// /questions/18087696/express-framework-app-post-and-app-get
app.get('/questions/:id/:slug', function(req, res, next){
db.fetch(req.params.id, function(err, question){
console.log('Fetched question: '+req.params.slug');
res.locals.question = question;
res.render('question-view');
});
});
next():
If you defined your handling functions as function(req, res, next){} you can call next() to yield, passing the request back into the middleware chain. You might do this for e.g. a catchall route:
app.all('*', function(req, res, next){
if(req.secure !== true) {
res.redirect('https://'+req.host+req.originalUrl);
} else {
next();
};
});
Again, order matters, you'll have to put this above the other routing functions if you want it to run before those.
I haven't POSTed json before but #PeterLyon's solution looks fine to me for that.
TJ annoyingly documents this as app.VERB(path, [callback...], callback in the express docs, so search the express docs for that. I'm not going to copy/paste them here. It's his unfriendly way of saying that app.get, app.post, app.put, etc all have the same function signature, and there are one of these methods for each supported method from HTTP.
To get your posted JSON data, use the bodyParser middleware:
app.post('/yourPath', express.bodyParser(), function (req, res) {
//req.body is your array of objects now:
// [{id:134123, url:'www.qwer.com'},{id:131211,url:'www.asdf.com'}]
});

Resources