How to add variable numbers of parameter in url using expressJS? - node.js

I'm using express in a nodejs project to call an endPoint and print the parameters after it in console. The url can be:
/printInfo?id=xxx&value=xxx
or
/printInfo?id=xxx
or
/printInfo?value=xxx
How can I do this?

Assuming you just want to understand how to read the query string, you just read the values on the req.query variable. Here is a simple setup:
routes/index.js
var express = require('express');
var router = express.Router();
router.get('/printInfo', (req, res, next) => {
res.send({ id: req.query.id, value: req.query.value});
});
module.exports = router;
app.js
const express = require('express');
const indexRouter = require('routes/index');
const app = express();
app.use('/', indexRouter);
app.listen(3000, () => console.log(`Example app listening on port 3000!`));
Now, when you make a request to http://localhost:3000/printInfo?id=1&value=test you should see (I have the JSON Formatter extension installed):
{
"id": "1",
"value": "test"
}
Show up at that page.
Here is a gif showing how it looks on my machine:

It's not entirely clear to do with the data you get from the URL, but req.query contains whatever query parameters are in the URL and you can just iterate that object to see what's there:
for (let prop of Object.keys(req.query)) {
console.log(prop, req.query[prop]);
}
And, here's a simulated demonstration which can run in a local snippet, but you can use the same type of code on req.query in Express:
// define simulated req.query (this is built automatically in Express)
let req = {
query: {id: 34506, value: "$400.99"}
};
// iterate arbitrary properties of req.query
for (let prop of Object.keys(req.query)) {
console.log(prop, req.query[prop]);
}
Or, if you know what possible query parameters may be there and you just want to test which ones are there, you can just do like this:
if ("id" in req.query) {
// id property is present
console.log(req.query.id);
}
if ("value" in req.query) {
// value property is present
console.log(req.query.value);
}

Related

How do I get the full route path including the parameters from express or extend the request object to do so?

I have the following route in my express (version 4.17.1) API in a postTimecardCompany.js file:
const mongoose = require('mongoose');
const Timecard = require('./../models/timecard');
function postTimecardCompany(server) {
server.post('/api/v1/timecard/:userId', (req, res) => {
// Insert timecard data into the database
Timecard.create(data, (error, result) => {
// Check for errors
if (error) {
res.status(500).end();
return;
}
// Respond
res.status(200).send({timecardId: result._id});
});
});
}
module.exports = postTimecardCompany;
The route (among other routes) is loaded via the following mechanism by server.js file:
[
'postTimecardCompany',
'anotherRoute',
'someOtherRoute',
'andSoOn...'
].map((route) => {
require('./core/routes/' + route + '.js').call(null, server)
});
I have a middleware (in server.js file) where I check which route is being called.
server.use((req, res, next) => {
// If route is "/api/v1/timecard/:userId" do something
});
I have found various solutions which do nearly what I am looking for, but not exactly.
For example, if I post to the route with a data parameter userId value of "123f9b" then req.originalUrl gives an output of "/api/v1/timecard/123f9b."
What i'm looking to get is the original route path with the parameters in it so for a request of "/api/v1/timecard/123f9b" it would be: "/api/v1/timecard/:userId."
How do I get this functionality in express or extend express to get the original route path with parameters in the request object?
if you want to use from your approach, it's is impossible, after that your approach is not standard in express check the documentation, if you want get routes in a middleware you should try like this:
server.js
const express = require('express')
const server = express()
const postTimecardCompany = require('./routes/postTimecardCompany.js')// don't use map()
server.use("/",postTimecardCompany)//use the routes
server.listen(6565,()=>console.log(`Listening to PORT 6565`))
routes of postTimecardCompany.js
use Router of express and export router, and you can use middleware before each route you want, there are many ways to use middleware in routes, check the documentation
const express = require("express");
const router = express.Router();
const middleware = require('../middleware');//require middlewares
router.post("/api/v1/timecard/:userId", middleware,(req, res) => {
// Insert timecard data into the database
console.log(req.route.path);
});
module.exports = router;
middleware.js
module.exports = ((req, res, next) => {
console.log(req.route.path);
next()
});

Express - get value of path matching string

Question
I've got several nested routers, and would like to get access to the whole string that the request's path matched. It's a little hard to say with english, so take a look at this code:
const express = require('express')
const app = express()
const router1 = express.Router()
const router2 = express.Router()
// set up router 2 paths
router2.get('/path2/:param2', (req, res, next) => {
const someVar = req.something // the value I'll talk about in a second
return res.status(200).send({ someVar })
})
// set up router1 paths
router1.use('/path1/:param1', router2)
// connect the routers behind a base url
app.use('/api/v1', router1)
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
If I were to make a GET request with:
curl -X GET http://localhost:3000/api/v1/path1/myparam1/path2/myparam2
I want that to return an object like this:
{
"someVar": "/api/v1/path1/:param1/path2/:param2"
}
Context
I have middleware in my app which logs the path to an elasticsearch cluster, and I'd like the cluster to group paths by the string they used to match the request, rather than the request itself. That way I can get a visual of which request endpoints are being hit the most.
// you need to set mergeParams: true on the router,
// if you want to access params from the parent router
var router1 = express.Router({mergeParams: true});

Execute a function with parameters passed to an express server?

I want to call a function using the parameters passed to an express call. Here's an example tying to do a simple console.log inside a function called inside the app.get():
// server.js
const express = require('express')
const app = express()
const port = process.env.PORT || 3001
function processRequest(api_key, another_value) {
console.log(api_key, another_value)
}
app.get('/api', function(req, res) {
let api_key = req.query.api_key
let another_value = req.query.another_value
processRequest(api_key, another_value)
res.json({api_key, another_value})
})
app.listen(port)
console.log("Started server")
and a simple test
const axios = require('axios')
function test() {
axios.get('localhost:3001/api?api_key=testkey&another_value=anothervalue', res => console.log(res.data))
}
test()
I know i'm missing something simple here.
Thanks ya'll
Use req.query.somevalue to get query params from request.
req.param only works for URL params like api/distance/:id
Some from docs:
(req.params) Checks route params, ex: /user/:id
(req.query) Checks query string params, ex: ?id=12 Checks urlencoded body params

How to pass variable from app.js to routes/index.js?

I'm using shrinkroute https://npmjs.org/package/shrinkroute to make links in nodejs. I get error 500 ReferenceError: shrinkr is not defined
How to pass shrinkroute to routes/index.js? Is there a better way to create url by passing query string args?
//app.js
var app = express();
var shrinkr = shrinkroute( app, {
"user": {
path: "/user/:id?",
get: routes.showOrListUsers
}
});
//url method works in app.js
var url = shrinkr.url( "user", { id: 5, page:40, type:'a' } );
console.log(url);
app.use( shrinkr.middleware );
//routes/index.js
exports.showOrListUsers = function(req, res, next) {
console.log(req.params);
//shrinkr errors out in index.js
var url2 = shrinkr.url( "users", {name: "foo"});
console.log(url2);
}
One solution would be to store shrinkr in your app object using app.set:
// app.js
...
app.set('shrinkr', shrinkr);
...
In routes/index.js, you can access it through the req.app or res.app objects:
exports.showOrListUsers = function(req, res, next) {
var shrinkr = req.app.get('shrinkr');
...
};
A bit late to the party, but the following works as well:
app.js
var my_var = 'your variable';
var route = require('./routes/index')(my_var);
app.get('/', route);
and meanwhile in route.js
var express = require('express')
, router = express.Router()
// Router functions here, as normal; each of these
// run only on requests to the server
router.get('/', function (req, res, next) {
res.status(200).end('Howdy');
});
module.exports = function(my_var){
// do as you wish
// this runs in background, not on each
// request
return router;
}
Two easy ways to achieve what you want:
1. Accessing your shrinkroute instance from within your route
Simple as that. Nothing else is required after Shrinkroute is setup.
exports.showOrListUsers = function(req, res, next) {
var shrinkr = req.app.shrinkroute;
console.log( "Route: " + req.route.name ); // ta-da, made available by Shrinkroute
// do your URL buildings
};
2. Using the middleware
If you don't want be tempted with non URL building methods of Shrinkroute, you can use the middleware, which will make available to you some helpers in your route and in your template (via locals):
// app.js
app.use( shrinkr.middleware );
// routes/index.js
exports.showOrListUsers = function(req, res, next) {
console.log( "Route: " + req.route.name ); // ta-da, made available by Shrinkroute
req.buildUrl( "users", { name: "foo" } );
// or, if you want the full url with the scheme and host...
req.buildFullUrl( "users", { name: "foo" } );
};
And maybe you want to use them in your templates as well?
// templates/index.jade
a( href=url( "users", { name: "foo" } ) ) Foo profile
a( href=fullUrl( "users", { name: "foo" } ) ) Foo profile
This method has the advantage that you don't get direct access to route setters inside a route.
Disclaimer: I'm the author of Shrinkroute.
you should import it. add following line to the very beginning of your code
var shrinkroute = require('shrinkroute');

How do I redirect in expressjs while passing some context?

I am using express to make a web app in node.js. This is a simplification of what I have:
var express = require('express');
var jade = require('jade');
var http = require("http");
var app = express();
var server = http.createServer(app);
app.get('/', function(req, res) {
// Prepare the context
res.render('home.jade', context);
});
app.post('/category', function(req, res) {
// Process the data received in req.body
res.redirect('/');
});
My problem is the following:
If I find that the data sent in /category doesn't validate, I would like pass some additional context to the / page. How could I do this? Redirect doesn't seem to allow any kind of extra parameter.
There are a few ways of passing data around to different routes. The most correct answer is, of course, query strings. You'll need to ensure that the values are properly encodeURIComponent and decodeURIComponent.
app.get('/category', function(req, res) {
var string = encodeURIComponent('something that would break');
res.redirect('/?valid=' + string);
});
You can snag that in your other route by getting the parameters sent by using req.query.
app.get('/', function(req, res) {
var passedVariable = req.query.valid;
// Do something with variable
});
For more dynamic way you can use the url core module to generate the query string for you:
const url = require('url');
app.get('/category', function(req, res) {
res.redirect(url.format({
pathname:"/",
query: {
"a": 1,
"b": 2,
"valid":"your string here"
}
}));
});
So if you want to redirect all req query string variables you can simply do
res.redirect(url.format({
pathname:"/",
query:req.query,
});
});
And if you are using Node >= 7.x you can also use the querystring core module
const querystring = require('querystring');
app.get('/category', function(req, res) {
const query = querystring.stringify({
"a": 1,
"b": 2,
"valid":"your string here"
});
res.redirect('/?' + query);
});
Another way of doing it is by setting something up in the session. You can read how to set it up here, but to set and access variables is something like this:
app.get('/category', function(req, res) {
req.session.valid = true;
res.redirect('/');
});
And later on after the redirect...
app.get('/', function(req, res) {
var passedVariable = req.session.valid;
req.session.valid = null; // resets session variable
// Do something
});
There is also the option of using an old feature of Express, req.flash. Doing so in newer versions of Express will require you to use another library. Essentially it allows you to set up variables that will show up and reset the next time you go to a page. It's handy for showing errors to users, but again it's been removed by default. EDIT: Found a library that adds this functionality.
Hopefully that will give you a general idea how to pass information around in an Express application.
The easiest way I have found to pass data between routeHandlers to use next() no need to mess with redirect or sessions.
Optionally you could just call your homeCtrl(req,res) instead of next() and just pass the req and res
var express = require('express');
var jade = require('jade');
var http = require("http");
var app = express();
var server = http.createServer(app);
/////////////
// Routing //
/////////////
// Move route middleware into named
// functions
function homeCtrl(req, res) {
// Prepare the context
var context = req.dataProcessed;
res.render('home.jade', context);
}
function categoryCtrl(req, res, next) {
// Process the data received in req.body
// instead of res.redirect('/');
req.dataProcessed = somethingYouDid;
return next();
// optionally - Same effect
// accept no need to define homeCtrl
// as the last piece of middleware
// return homeCtrl(req, res, next);
}
app.get('/', homeCtrl);
app.post('/category', categoryCtrl, homeCtrl);
I had to find another solution because none of the provided solutions actually met my requirements, for the following reasons:
Query strings: You may not want to use query strings because the URLs could be shared by your users, and sometimes the query parameters do not make sense for a different user. For example, an error such as ?error=sessionExpired should never be displayed to another user by accident.
req.session: You may not want to use req.session because you need the express-session dependency for this, which includes setting up a session store (such as MongoDB), which you may not need at all, or maybe you are already using a custom session store solution.
next(): You may not want to use next() or next("router") because this essentially just renders your new page under the original URL, it's not really a redirect to the new URL, more like a forward/rewrite, which may not be acceptable.
So this is my fourth solution that doesn't suffer from any of the previous issues. Basically it involves using a temporary cookie, for which you will have to first install cookie-parser. Obviously this means it will only work where cookies are enabled, and with a limited amount of data.
Implementation example:
var cookieParser = require("cookie-parser");
app.use(cookieParser());
app.get("/", function(req, res) {
var context = req.cookies["context"];
res.clearCookie("context", { httpOnly: true });
res.render("home.jade", context); // Here context is just a string, you will have to provide a valid context for your template engine
});
app.post("/category", function(req, res) {
res.cookie("context", "myContext", { httpOnly: true });
res.redirect("/");
}
use app.set & app.get
Setting data
router.get(
"/facebook/callback",
passport.authenticate("facebook"),
(req, res) => {
req.app.set('user', res.req.user)
return res.redirect("/sign");
}
);
Getting data
router.get("/sign", (req, res) => {
console.log('sign', req.app.get('user'))
});
we can use express-session to send the required data
when you initialise the app
const express = require('express');
const app = express();
const session = require('express-session');
app.use(session({secret: 'mySecret', resave: false, saveUninitialized: false}));
so before redirection just save the context for the session
app.post('/category', function(req, res) {
// add your context here
req.session.context ='your context here' ;
res.redirect('/');
});
Now you can get the context anywhere for the session. it can get just by req.session.context
app.get('/', function(req, res) {
// So prepare the context
var context=req.session.context;
res.render('home.jade', context);
});
Here s what I suggest without using any other dependency , just node and express, use app.locals, here s an example :
app.get("/", function(req, res) {
var context = req.app.locals.specialContext;
req.app.locals.specialContext = null;
res.render("home.jade", context);
// or if you are using ejs
res.render("home", {context: context});
});
function middleware(req, res, next) {
req.app.locals.specialContext = * your context goes here *
res.redirect("/");
}
You can pass small bits of key/value pair data via the query string:
res.redirect('/?error=denied');
And javascript on the home page can access that and adjust its behavior accordingly.
Note that if you don't mind /category staying as the URL in the browser address bar, you can just render directly instead of redirecting. IMHO many times people use redirects because older web frameworks made directly responding difficult, but it's easy in express:
app.post('/category', function(req, res) {
// Process the data received in req.body
res.render('home.jade', {error: 'denied'});
});
As #Dropped.on.Caprica commented, using AJAX eliminates the URL changing concern.
Update 2021:
i tried url.format and querystring and both of them are deprecated, instead we can use URLSearchParams
const {URLSearchParams} = require('url')
app.get('/category', (req, res) =>{
const pathname = '/?'
const components ={
a:"a",
b:"b"
}
const urlParameters = new URLSearchParams(components)
res.redirect(pathname + urlParameters)
})
I use a very simple but efficient technique
in my app.js ( my entry point )
I define a variable like
let authUser = {};
Then I assign to it from my route page ( like after successful login )
authUser = matchedUser
It May be not the best approach but it fits my needs.
app.get('/category', function(req, res) {
var string = query
res.redirect('/?valid=' + string);
});
in the ejs you can directly use valid:
<% var k = valid %>

Resources