Dynamically remove path - node.js

Is there a way to dynamically remove a path from express so that the endpoint will return 404. For example:
app.get('./test', handle);
Later I would like to do something like:
app.get('./test').remove();

I would put a test in your handler rather than removing the path, something like this:
var handle = function(req, res) {
if (yourCondition) {
res.status(404);
res.send('This path has been removed');
}
}

Related

req.params.id returning undefined when id is defined in separate file

When I use req.params.id with mongoose it returns undefined. I am fairly certain this is because I define the id parameter in my app.js and not my route file.
Route file:
//NEW - Form for adding new course
router.get("/new", function(req, res) {
// find course by id
Course.findById(req.params.id).exec(function(err, foundCourse) {
if(err) {
res.redirect("back");
} else {
//show template with correct id
res.render("lectures/new", {course: foundCourse});
}
});
});
App.js file:
app.use("/courses/:id/lectures", lectureRoutes);
Is there any way to fix this so that I can access the id parameter from the route file?
EDIT:
the path I use in my browser:
http://localhost:7000/courses/5a4111286ae1111f541c3d88/lectures/new
For this to work you have to enable the option called mergeParams.
const router = express.Router({ mergeParams: true });
See the documentation here.

"Dynamic route" with expressjs

I want to create a route which can change while the program is running.
Example : app.get('/',function(req,res){/*Something here*/}; This is a normal route.
I want to replace the '/' with a variable which can be replaced with a random number. After that I'll create a qrcode with a nodejs module and the user who scans this qrcode will confirm a kind of transaction.
If you understand my idea and you have a solution, I'll take it.
As #Louy said, use parameters:
var getQRCode = require('./yourQRCodeModule');
app.param('qrcode', function(req, res, next, qrcode) {
// qrcode will be "1234" if your request path was "/1234"
console.log('checking qrcode: %s', qrcode);
// get the qrcode from some asynchronous function
getQRCode(qrcode, function callback(err, qrcode) {
// if this number was not a valid dynamic path, return an error from your module
console.log('qrcode was %s', (!err && qrcode) ? 'valid' : 'invalid');
if (err) {
next(err);
} else if (qrcode) {
req.qrcode = qrcode; // object from your module
next();
} else {
next(new Error('failed to load QR code'));
}
});
});
app.get('/:qrcode', function (req, res) {
// req.qrcode will be the object from your module
// if the number was invalid, this will never be called
});
What I'm trying to point out is that you're thinking of this scenario differently than how express approaches the problem. You want a one-time route with a specific qrcode, but these kind of routes don't exist in express. So here's what I understand your ideal solution to look like:
server creates "azjzso1291084JKioaio1" for a qrcode
you register something like app.getOnce("azjzso1291084JKioaio1", function(req, res){...})
first time the request gets called, it's removed from your express router
Here's what I'm suggesting:
server creates "azjzso1291084JKioaio1" for a qrcode
your module stores this qrcode either in a database or in memory, within your module, e.g. var qrcodes = {}; qrcodes["azjzso1291084JKioaio1"] = {some: 'object'};
your app.param asynchronous function based on the example given in step 2 could look like this:
// yourQRCodeModule.js
var qrcodes = {};
qrcodes["azjzso1291084JKioaio1"] = {some: 'object'};
module.exports = function getQRCode(qrcode, callback) {
if (qrcodes[qrcode]) {
var obj = qrcodes[qrcode]; // copy object
delete qrcodes[qrcode]; // remove from memory here
callback(null, obj);
} else {
// invalid path
callback(new Error('invalid QR code'), null);
}
};
Now notice if you request /azjzso1291084JKioaio1 twice, the second time fails. This is how you intend it to work, if I am not mistaken.

Node.JS equivelant to getContextPath, getServletPath?

I'm working on a webserver, which will load various modules for various 'web applications' on the same domain.
In the following example,
createServer(function (req, res) { // crude request routing example
var path = url.parse(req.url).pathname
if(path.match(/^\/cats(?:\/|$)/))
require('./cats.js')(req, res)
else if(path.match(/^\/dogs(?:\/|$)/))
require('./dogs.js')(req, res)
else
require('./404.js')(req, res)
})
the if statement checks for a matching context path, and routes it to the appropriate module.
Now the module cats.js looks something like this:
module.exports = function (req, res) {
var path = url.parse(req.url).pathname
// HOW can I get context path and path info? What variables should I use?
if(req.path == '/cats/add') {
//....
} else if(req.path == '/cats/delete') {
//....
} else
// 404
}
The problem is, down the road I will be updating the context path, so instead of /cats, users will have to go to /somethingelse to get to cats.js
For this reason, cats.js should not be checking for /cats/add, but should instead look for $CONTEXT/add.
What is a good way to pass the 'context path' and the 'path info' to cats.js? I'm thinking about making something up and tacking it onto the req object, but surely this is a common problem and there is a generally accepted correct solution?
You could have cat.js export a function which takes a path arg and uses it to create the request handler on the fly:
module.exports = function(context){
return function (req, res) {
var path = url.parse(req.url).pathname
if(req.path == '/'+context+'/add') {
//....
}
//....
}
}
As others mentioned, Express.JS has this capabilities built in and would be a generally accepted solution, other than that you're free to roll however you want.

Pass a variable to view in every request, Node.js Express

I have some code that is repeated among my routes, and I always pass to the view some resulting variables from that repeated code.
Example:
/* GET /events/list */
router.get('/events/list', function(req, res) {
var blah = someFunctionThatAnalyzesUserCookie();
res.render('places/list', { title: 'Places', blah: blah });
});
/* GET /events/details */
router.get('/events/details', function(req, res) {
var blah = someFunctionThatAnalyzesUserCookie();
res.render('places/details', { title: 'Some place', blah: blah });
});
How can I refactor this?
I need to pass blah to all of my views and I want their logics clean, like this:
/* GET /events/list */
router.get('/events/list', function(req, res) {
res.render('places/list', { title: 'Places' });
});
/* GET /events/details */
router.get('/events/details', function(req, res) {
res.render('places/details', { title: 'Some place' });
});
I googled for a while but only found how to execute something in every request, like this:
app.use(function(req, res, next) {
doSomethingInEveryRequest();
next();
});
But I can't figure out how to pass a variable to the view in every request.
Also I read about app.locals, but I guess that is more suited for constants. My passed variable depends on the user's cookies so is a... variable.
Can you try something like bellow:-
var renderPage = function(path,fileName,title){
router.get(path,function(req,res){
var blah = someFunctionThatAnalyzesUserCookie();
res.render(fileName,{title:title, blah:blah});
});
}
renderPage('/events/list','events/list','Places');
renderPage('/events/details','events/details','Some Place');
I think you can use Express's middleware called "Cookie-Parser".
Here is a link to its documenation: https://github.com/expressjs/cookie-parser/blob/master/README.md

How to create my own module of functions in a node.js app

I'm building my node.js app which has the following structure:
server.js
controllers/user.js
server.js require the user.js controller with:
require('./controllers/user.js').route(app, mongoose);
the controller/user.js file is like:
function route(app, mongoose){
function route(app, mongoose){
// Create new User item
app.post('/user/create', function(req, res){
...
}
// Edit user
app.put('/user/:id/edit', function(req, res){
...
}
...
}
module.exports.route = route;
This is working fine.
I know want to had middleware in the Edit user function for instance so it looks like:
...
app.put('/user/:id/edit', loadUser, function(req, res){
...
If I define loadUser function right above this line it's working fine. When I add all the middleware fonction in a file './lib/middleware.js' and when I try to load that file in user.js with:
require('../lib/middleware.js').create(); // Create is the exported function
this does not work and I have the error message saying that loadUser is an unknow function.
Any idea ?
** UPDATE **
I have updated the files such that, in server.js (main file) I have:
...
var middleware = require('./lib/middleware.js');
...
require('./controllers/user.js').route(app, mongoose, middleware);
...
In middleware.js, I then have:
function create() {
function loadUser(req, res, next) {
// You would fetch your user from the db
var user = users[req.params.id];
if (user) {
req.user = user;
next();
} else {
next(new Error('Failed to load user ' + req.params.id));
}
}
return module;
}
In controllers/user.js I have
function route(app, mongoose, middleware){
...
// Modify an user
app.put('/user/edit', middleware.loadUser, function(req, res){
...
}
...
}
When I run the app (node server.js) I then have the following error:
Error: PUT route /user/edit requires a callback
I am not sure to return the correct thing within middleware.js, not really familiar with module stuff yet. I also tried the "module.exports.create = create;" but same thing.
UPDATE WITH ANOTHER TRY
what if I create a module for the function ? In ./lib/middleware.js I would have:
(function(){
var middleware = {};
middleware.loadUser = function () {
console.log("loadUser");
}
return middleware;
}());
And in server, I call it:
var middleware = require('./lib/middleware.js');
middleware.loadUser;
It seems to me that should work but it does not...
"global" scope in a file is actually module scope. Just by creating a function in a different file it does become in scope in your original file.
What you want to do instead is
// routes.js
var middleware = require("../lib/middleware.js").create();
app.put('/user/:id/edit', middelware["loadUser"], function(req, res){
You will find that global variables actually write to module in their scope.
Then your function loadUser() { ... } should exist in the module property.
// middleware.js
function create() {
...
return module;
}
If you return module from your create function your returning global scope.
[Edit]
function create() {
function loadUser(req, res, next) {
// You would fetch your user from the db
var user = users[req.params.id];
if (user) {
req.user = user;
next();
} else {
next(new Error('Failed to load user ' + req.params.id));
}
}
return module;
}
You either need to add module.loadUser = loadUser or define loadUser in module scope. I.e. outside the create function.
[Further Edit]:
A standard setup would be something like:
// middleware.js
(function() {
function loadUser(...) {
...
}
...
module.exports.loadUser = loadUser;
})();
//otherfile.js
var middle = require("middleware");
middle.loadUser();
When code is loaded using require() it doesn't put anything into the global context. You have to bind it to a variable.
For example when you require your middleware file, you are able to call create() only because the module.exports object is returned from the require() function and you are able to access the call site directly. Here is how you would keep a reference to the require()d code so you could access it later:
var middleware = require('../lib/middleware.js');
middleware.create();
and probably this is what you want:
app.put('/user/:id/edit', middleware.loadUser, function(req, res) ...
update:
As raynos pointed out, no function wrapper is advised in this case. See his comment.
Note that I wrapped the loadUser function reference in an anonymous function. Leaving the code as you had it would have worked as long as your code didn't rely on the value of 'this' internally.
update:
I think I misunderstood what you were trying to do with create(). The above works if you define your loadUser() function as directly part of the module. If you need to do something else tricky in your Create() function you can use what I wrote above by doing something like
var loadUser = middleware.create();
Then you'll have the loadUser function defined in scope.

Resources