How can we transfer id data with node index.js?id=1 - node.js

How can we transfer id data with node?
node index.js?id=1
var express = require('express');
var app = express();
app.get('/:id', function(req, res) {
res.send('id: ' + req.params.id);
console.log(req.params.id);
});

In nodejs.org there's a piece of documentation where the functionality you desire is explained in a clear and simple way (https://nodejs.org/en/knowledge/HTTP/clients/how-to-access-query-string-parameters/).
Basically, what you are using in the code you showed returns the part of the path where you use the ":[name]" (a subdirectory).
What you actually want to get are the query string parameters by using url.parse(req.url,true).query which returns an object with a set of key:value pairs with the name of each parameter and respective value.
Be aware that to use that line of code you'll need at least to require the url module.
I hope I made myself clear and that my answer helps you!

Related

How do I access URL parameter after i've routed my express app to another file?

My main express server is called app.js in Node.js.
app.use("/login", require(./routes/login));
app.use("/:id", require("./routes/users"));
When I try to access the URL parameter, it returns undefined.
I tried logging req.params:
const express = require('express');
const router = express.Router();
router.get('/dashboard', (req, res) => {
res.send(`Current Ornament Status and Data for ${req.params}`);
});
module.exports = router;
It gives me an empty array.
I suppose that it the parameter is inaccessible in another file after routing. Could you suggest a workaround?
I think you're missing some fundamental bits about express.js routing for this to make sense.
The requires line means it is loading another piece of code. So you need to show us that too.
The :id thing requires a longer explanation.
Let's say I want the server to process the URL /finduser/23
Where 23 can vary, could be just about any number. I am NOT going to write 99 different versions of router.get, right?
router.get("/finduser/1",...
router.get("/finduser/2",...
router.get("/finduser/3",...
No, what we do is turn that into a parameter
router.get("/finduser/:id",...
Then whatever number we pass turns into req.params.id, assume router passes req,res
EX: If we pass URL /finderuser/15, then req.params.id = 15
If you just pass /finduser then req.params.id gets NOTHING.
Full details are available here
http://expressjs.com/en/guide/routing.html#route-parameters
Your example:
router.get('/dashboard', (req, res)
Doesn't have ANY parameters. so req.params.id has nothing.

Express.js unique var per request outside routing

In my express application I have a module called helpers thats is required in almost all my routes and modules. This module has a logger method that logs to fluentd (but that's unimportant). While building the data to log I'd like to add a unique identifier of the request, so that all the logs written for the same request have the same unique ID. Using a global var in the app entry point app.use doesn't work because this var would be overwritten every time a new request hits, so the global uuid will change would obviously change in case of high load or long running tasks. The res.locals is not available outside routing, so I can't use it for this matter. Is there a way to create a var that would be unique per request and available in every module or maybe a way to access the res.locals data outside routing? Thank you
EDIT
Maybe an example will help understand better the question.
Suppose I have a module called helpers.js like this:
let helpers = {};
helpers.log = (logData, logName) => {
fluentLogger.emit('', {
name: logName,
//uuid: the needed uuid,
message: logData
});
}
module.exports = helpers;
Now obviously I can do this in my app.js entry point:
app.use(function (req, res, next) {
res.locals.uuid = uuid.v4();
next();
});
and then in every loaded middleware module that requires helpers(adding a new param to the helpers.log method):
const helpers = require('helpers');
router.post('/', (req, res, next) => {
helpers.log('my log message', 'myLogName', res.locals.uuid);
next();
});
and this will normally work. But suppose a big or middle size project where there are hundreds of custom modules and models (not middlewares) and a module may require other modules that require other modules that require finally the helpers module. In this case I should pass the res.locals.uuid as a parameter to every method of every method so that I have it available in the logger method. Not a very good idea. Suppose I have a new module called dbmodel.js that is required in a middleware function:
const helpers = require('helpers');
let dbmodel = {};
dbmodel.getSomeData = (someParam) => {
//some logic
helpers.log('my log message', 'myLogName');
}
module.exports = dbmodel;
The dbmodel has no idea about the res.locals data if I don't pass it from the middleware, so the helpers.log method will also have no idea about this.
In PHP one would normally write a GLOBAL var in the application's entry point so a hypothetical logger function would have access to this global on every method request from whichever class of the application.
Hope this explanation will help :) Thank you
EDIT 2
The solution for this kind of problems is CLS. Thanks to #robertklep for the hint. A good slideshare explaining exactly the same problem (logger with unique ID) and explaining the CLS solutions can be found here: https://www.slideshare.net/isharabash/cls-and-asynclistener
I answered a very similar question here which will solve this problem.
I used to solve the problem the libraries node-uuid and continuation-local-storage. Take a look to the answer of this question and see if it helps:
NodeJS Express - Global Unique Request Id
And you want a bigger explanation, take a look here:
Express.js: Logging info with global unique request ID – Node.js
Yes you can do so by one method .
Every request comes to his routes pass that request inside the middleware.
Suppose you have
app.get('/', function(req, res) {
res.sendFile(path.join(public + "index.html"));
});
a request.
Place Middleware in it .and edit req field coming , in this way you will get the unique variable values for each request
check out this .
https://expressjs.com/en/guide/writing-middleware.html
Like this
var requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
app.use(requestTime)
app.get('/', function (req, res) {
var responseText = 'Hello World!<br>'
responseText += '<small>Requested at: ' + req.requestTime + '</small>'
res.send(responseText)
})
Here req.requestTime is unique for each request.

Node.js, Express.js and MongoDB - Security about user input with find and insert

I created a set of REST services based on Express.js to find some results stored in a Mongo Database. A very minimal version of the code for one of the services could be something like:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoClient = require('mongodb').MongoClient;
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get('/results/:name', function(req, res){
var name = req.params.name;
mongoClient.connect('mongodb://localhost/test', function (err, db) {
var collection = db.collection('results');
collection.find({ name: name }).toArray( function (err, docs) {
res.json({results: docs});
});
});
});
app.listen(3000);
I'm coming from Java and I've been beaten by SQL injections in the past. So I'm not at all comfortable with using the user's input directly in the find request. With my very thin knowledge of the subject, I tried several special characters ( } ) " ' ; and so on) but I've not been able to produce any weird result.
What could go wrong here? What kind of validations or checks should I implement to make sure that it is not possible to inject code or to make the program fail?
Now, let's do something stupid and let's trust the user to input a correct record:
app.post('/results/', function(req, res){
var record = req.body;
if( record.name ) {
mongoClient.connect('mongodb://localhost/test', function (err, db) {
var collection = db.collection('results');
collection.insert( record, function(err, doc){});
res.json({message: 'ok'});
});
}
});
How can I validate the schema of the input? And apart from filling the DB with thousand of gigantic inputs, is it possible to exploit this code to inject some code? If yes, how to prevent that?
Thanks a lot!
I would have put this as a comment but since I'm not yet allowed to do that i'll just put it as a responce.
I go into the details since I'm not the expert here but here is an article I've found to be really interresting about vulnerability when using mongo and node.js.
For validating the model, I use mongoose as a client to my mongoDB, it helps a lot as it has its own validators and you can as well make your own.
I hope it helps you into your search.
Mongodb access is api-based, as oposed to SQL that is language-based. SQL is a language, and if you let inputs from users to be inserted in the language, then it is easy to make code injection and do almost everything to your database.
MongoDB has a different approach, when you are doing a search, you call an API function to do the search, and this API function can only do searchs.
If you let the user choose the fields and the values, then he can make searchs that you don't expect, but that's all.
The same applies for inserts, updates and deletes, be careful of not letting the user to choose the fields and the values, because he can choose ones that you do not expects nor wants.

Cascade-like rendering with Express JS

With an express app running on a node server, how would I go about recursively searching for a render file from the full path right back to the beginning of the supplied URL.
For example, if someone was to hit my server with www.somewebsite.com/shop/products/product, the render engine would first check that there is an index.jade file in shop/products/product/. If none is found it would then check shop/products/, and subsequently shop/.
var express = require('express');
var app = express();
app.get('/*', function(req, res){
res.render(req.path + '/index.jade', function(err, html){
// some loopback code which alters the path and recalls the render method
})
});
The problem is that the response object is not passed to the render callback, so I'm unable to recall render on the response. I'm looking to create a loop because the URL paths may be any number of directories deep, so I can't just assume I only need to cascade for a definitive number of times.
Anyone see a way round this?
You should be able to use the response object from the closure. I think (assuming express allows you to call res.render a second time) you could use code like this answer to achieve what you want:
var express = require('express');
var app = express();
app.get('/*', tryRender);
function tryRender(req, res){
res.render(req.path + '/index.jade', function(err, html){
if (err) {
req.path = 'mynewpath';
tryRender(req, res);
}
})
}
Note: You will need to add a base case or this function will recurse infinitely if it doesn't find a view that works :D
In the event that express doesn't allow a subsequent call to res.render, you'll probably need to find out if the file exists on the file system yourself.

Express-js wildcard routing to cover everything under and including a path

I'm trying to have one route cover everything under /foo including /foo itself. I've tried using /foo* which work for everything except it doesn't match /foo. Observe:
var express = require("express"),
app = express.createServer();
app.get("/foo*", function(req, res, next){
res.write("Foo*\n");
next();
});
app.get("/foo", function(req, res){
res.end("Foo\n");
});
app.get("/foo/bar", function(req, res){
res.end("Foo Bar\n");
});
app.listen(3000);
Outputs:
$ curl localhost:3000/foo
Foo
$ curl localhost:3000/foo/bar
Foo*
Foo Bar
What are my options? The best I've come up with is to route /fo* which of course isn't very optimal as it would match way too much.
I think you will have to have 2 routes. If you look at line 331 of the connect router the * in a path is replaced with .+ so will match 1 or more characters.
https://github.com/senchalabs/connect/blob/master/lib/middleware/router.js
If you have 2 routes that perform the same action you can do the following to keep it DRY.
var express = require("express"),
app = express.createServer();
function fooRoute(req, res, next) {
res.end("Foo Route\n");
}
app.get("/foo*", fooRoute);
app.get("/foo", fooRoute);
app.listen(3000);
The connect router has now been removed (https://github.com/senchalabs/connect/issues/262), the author stating that you should use a framework on top of connect (like Express) for routing.
Express currently treats app.get("/foo*") as app.get(/\/foo(.*)/), removing the need for two separate routes. This is in contrast to the previous answer (referring to the now removed connect router) which stated that "* in a path is replaced with .+".
Update: Express now uses the "path-to-regexp" module (since Express 4.0.0) which maintains the same behavior in the version currently referenced. It's unclear to me whether the latest version of that module keeps the behavior, but for now this answer stands.
It is not necessary to have two routes.
Simply add (/*)? at the end of your path string.
For example, app.get('/hello/world(/*)?' /* ... */)
Here is a fully working example, feel free to copy and paste this into a .js file to run with node, and play with it in a browser (or curl):
const app = require('express')()
// will be able to match all of the following
const test1 = 'http://localhost:3000/hello/world'
const test2 = 'http://localhost:3000/hello/world/'
const test3 = 'http://localhost:3000/hello/world/with/more/stuff'
// but fail at this one
const failTest = 'http://localhost:3000/foo/world'
app.get('/hello/world(/*)?', (req, res) => res.send(`
This will match at example endpoints: <br><br>
<pre>${test1}</pre>
<pre>${test2}</pre>
<pre>${test3}</pre>
<br><br> Will NOT match at: <pre>${failTest}</pre>
`))
app.listen(3000, () => console.log('Check this out in a browser at http://localhost:3000/hello/world!'))
In array you also can use variables passing to req.params:
app.get(["/:foo", "/:foo/:bar"], /* function */);
For those who are learning node/express (just like me): do not use wildcard routing if possible!
I also wanted to implement the routing for GET /users/:id/whatever using wildcard routing. This is how I got here.
More info: https://blog.praveen.science/wildcard-routing-is-an-anti-pattern/

Resources