How to Get QueryString in Node/Express? - javascript

How can I send/get the querystring from one page to another?
I am using: node version v0.12.3000 express 3.20.3
I am trying this way:
page1.js
function p1(req, res){
res.render('page1');
};
exports.p1= p1;
exports.post_enviar = function(req, res){
var param1 = req.body.param1;
res.render('page2', { param1 });
}
page2.js
function p2(req, res){
res.render('page2');
};
exports.p2= p2;
exports.get_enviar = function(req, res){
var param1 = req.params.param1;
console.log("param1: "+param1);
}
Thanks!

Short answer: you can't do that.
Long(er) answer: what you're trying to do involves either queuing a message in one route handler that would be consumed by another route, or otherwise simply sharing state between them.
The post_enviar export is stateless. It doesn't reference any data outside itself.
To demonstrate: (warning, don't do this)... If you had two modules for route controllers like this:
// route1controller.js
var lastQuery = {};
module.exports.route1controller = function (req, res, next) {
lastQuery = req.params;
res.render(...);
}
module.exports.lastQuery = lastQuery;
and
// route2controller
var lastQuery = require('./path/to/route1controller').lastQuery;
module.exports.route2controller = function (req, res, next) {
res.send(lastQuery);
}
Then the page rendered by route2controller will get the object (or array) of parameters that was last sent in a request to the route1controller. This is just a crude way of sharing state between the two controllers, and you really don't want to do this. Consider a more manageable solution, like logging (writing to a flat file, or database) requests to a given route, and then parsing them in a human readable way on another page.
If you're looking to get real-time information on one page about requests to another page, you'll need to look into more sophisticated solutions like websockets, or a polling for current data.

Related

Issue with multiple routes in one file - only two out of three work, the last one won't work

I'm working on making an API using express and MySQL. I'm having issues with my routes. I have it in a separate folder, requiring the different controller files and exporting the router at the end. Here's the issue. The last router.get function will not work. I can swap it and whatever is last will not work. I'll get back an empty array. I'm at a loss as to what can be wrong. Here's my code, the routes file:
const express = require('express');
const router = express.Router();
const getEmployeesController = require('../controllers/getEmployees');
const getEmployeesByIdController = require('../controllers/getEmployeesById');
const getEmployeesByFirstNameController = require('../controllers/getEmployeesByFirstName');
router.get('/', getEmployeesController.getEmployees);
router.get('/:id', getEmployeesByIdController.getEmployeesById);
router.get('/:first_name', getEmployeesByFirstNameController.getEmployeesByFirstName);
module.exports = router;
The 'first_name' router worked when it was second, after the '/', but now it won't. Same with the 'id', worked when its second, but not when it's third.
Here's the controller function, one as an example:
const mysql = require('mysql')
const pool = require('../mysql/connection')
const { handleSQLError } = require('../mysql/error')
const getEmployeesById = (req, res) => {
let sql = "SELECT ?? FROM ?? WHERE ?? = ?"
sql = mysql.format(sql, ['*', 'employees', 'emp_no', req.params.id])
pool.query(sql, (err, rows) => {
if (err) return handleSQLError(res, err)
return res.json(rows);
})
}
module.exports = { getEmployeesById };
/:first_name and /:id match the exact same URLs so only the first one you register is going to get all the matching URLs. They both match /anything.
You really can't define routes like that. There's no way Express knows which route handler you want to use with /anything is the requested URL.
Instead, you need to define a route structure where those two types of URLs are different and you can design a route handler that will uniquely catch each one. I personally don't ever use top level wildcard routes like this because they match every top level URL and they prohibit you using top level URLs for any other purpose in your site.
Instead, you might change your URL design to do this:
router.get('/id/:id', ...)
router.get('/firstname/:firstname', ...);
Then, it would be completely clear from the URL what type of resource was being requested and each route would match only the appropriate URLs.

Node.js same uri but different parameters

I'm doing a simple library API with Node.js and express. To fetch a specific book with ISBN or books within a specific genre, I have the following functions:
/api/books/isbn
router.get('/:isbn', function (req, res)
{
var isbn = req.params.isbn
})
/api/books/query
router.get('/:genre', function (req, res)
{
var genre = req.params.isbn
})
So first of all, this will not work because it will only go to the first function regardless of what the input is. Another thing I tried and that worked, was to make only one function that extracts the query parameters:
router.get('/', function (req, res)
{
var isbn = req.query.isbn
var genre = req.query.genre
})
Using this approach I could get the different values by doing calls like /api/books?genre=Adventure or /api/books?isbn=1231230912
But I feel it would make more sense to do it the first way, i.e /api/books/adventure or /api/books/isbn.
So, which way is the 'right' way? And if it's the first one, how can I design the functions so that they can extract the right values?
I think the second approach you tried should also be ok.
However, if you asked me to do this. I will create below apis:
/api/books/genre/Adventure
/api/books/isbn/1231230912
This helps to have clear distinctions between the apis and makes them maintainable and readable for future.
To save the time of writing 2 route handlers, you can write only one route handler function and pass either genre or isbn as parameter.
Try using one route, and by trying to parse the parameter to a number you can check if it's an isbn or genre.
If NaN then genre else isbn
You could do like so :
// /api/
router.get('/isbn/:isbn', function (req, res)
{
var isbn = req.params.isbn
})
// /api/books/query
router.get('/genre/:genre', function (req, res)
{
var genre = req.params.genre
})
This will work and this is the most used format.
And if you wan't to have only one uri then do like so :
// /api/books/isbn
router.get('/', function (req, res)
{
var isbn = req.query.isbn
var genre = req.query.genre
if (isbn)
res.redirect('/isbn/' + isbn);
else if (genre)
res.redirect('/genre/' + genre);
})

How can I dynamically assign a database path in Express.js based on login?

I have a backend service that I would like to use as a single point of entry for my web application, and dynamically assign a database path based on the user login.
I realize that this is not a scalable solution. I intend to use it during a testing period with several clients (accessing the ALPHA database), and also setting up a demo (accessing the SAND database).
I have the following module that I have written as a simple test to see if the login is for the demo user, all other logins will go to the other resource:
config.js
var express = require('express');
var app = express();
module.exports.dbPath = function (login){
console.log('login - ', login);
if (login === 'demo#mysite.com'){
return process.env.DB_SAND;
} else {
return process.env.DB_ALPHA;
}
};
My question is, how can I manage each unique login and assign a globally accessible reference for that session to direct each user session consistently to the correct database?
Am I overcomplicating this? If there is a different approach that would be a better practice I would welcome a suggestion in another direction.
I would use it as a middleware, and attach it to the req object for each user, something similar this:
module.exports = {
dbPath: function(req, res, next){
var login = req.body.login;
console.log('login - ', login);
if (login === 'demo#mysite.com'){
req.dbPath = 'DB_SAND';
} else {
req.dbPath = 'DB_ALPHA';
}
next();
}
};

Node.js Express app insert app.local.setting only once when logged in

I have a node.js + Express app. I am using Passport for user login. There is a system settings table in my database which I want to read from when a user successfully logs in and then create app.locals.setting_name local variables from it, which will be used during the lifetime of the application.
The settings table has the Name and Value columns which represent the setting name and its corresponding value. So something like: Name - SUPPORT_EMAIL and Value - support#email.com, as an example.
So I would have app.locals.SUPPORT_EMAIL value set as support#email.com
Here is the code I have so far:
app.js
var settingsObj = require('./config/appSettings.js');
app.use(function(req, res, next) {
...
...
settingsObj.getApplicationSystemSetting(req.user, app);
next();
});
appSettings.js
exports.getApplicationSystemSetting = function() {
connectionPool.getConnection(function(err, connection){
connection.query('select Name, Value from SystemSettings', function(err, rows){
if(err) {
winston.log('info', '--------------------- ERROR: ' + err);
return;
}
console.log('-------------- settings: ' + JSON.stringify(rows));
for(var i = 0; i < rows.length; i++) {
var setting = rows[i];
app.locals.setting.Name = setting.Value;
}
});
});
}
There are however two problems I am facing:
1) The app.use calls the settings code every time I go to a new page. I just want this code to be called only once when the user logs in.
2) The app.locals are not set. If I do a debug app.locals.SUPPORT_EMAIL as undefined.
Any suggestions or ideas on how this can improve?
So, two things. app.use will, in fact, happen on every request. The easiest way to deal with your need is to simply have that middleware check for app.user and if it's not there call next() without doing anything else. So the middleware is called but doesn't try to set locals.
Second issue, your function that sets app.locals doesn't actually use the parameters you're passing it (note the function signature in your second code block), and it is async, so there's a good chance that the middleware is calling next() before it's ever executed. Change the function signature to:
function(user, locals, callback)
and then have the middleware pass 'next' as the callback. The locals object you pass should actually be res.locals as you only want to set the variable for that response, not the whole app.

What does a Node.js web service look like?

I am taking a look at Node.js and thinking about using it for building an API. From what I can tell, ExpressJS would be the web framework and is not what I'd be looking for to solve this.
So what would a web service look like? Would it simply be creating a server, talking to mongo and returning results? Also, what does routing look like? (I'd obviously want to 'design' the routes).
If Express would be your web framework, look at the express-resource (Github) middleware for routing an API. You define resources and it'll wire up REST-style routing for you with very little boilerplate.
app.resource('horses', require('./routes/horses'), { format: json })
Given the above, express-resource will hook up all the REST-style routes to actions you supply, returning JSON by default. In routes/horses.js, you export actions for that resource, along the lines of:
exports.index = function index (req, res) {
// GET http://yourdomain.com/horses
res.send( MyHorseModel.getAll() )
}
exports.show = function show (req, res) {
// GET http://yourdomain.com/horses/seabiscuit
res.send( MyHorseModel.get(req.params.horse) )
}
exports.create = function create (req, res) {
// PUT http://yourdomain.com/horses
if (app.user.canWrite) {
MyHorseModel.put(req.body, function (ok) { res.send(ok) })
}
}
// ... etc
You can respond with different representations:
exports.show = {
json: function (req, res) {
// GET http://yourdomain/horses/seabiscuit.json
}
, xml: function (req, res) {
// GET http://yourdomain/horses/seabiscuit.xml
}
}
Middlewares like express-resource can make life with Node and Express much easier, take a look through the examples on github to see if it'll do what you need.
Here is a stub that looks up a horse name from a Postgres database and returns the result as JSON. Clients would access would access the API by going to address such as http://yourdomain.com/api/horse/seabiscuit
app.get('/api/horse/:name', function(req, res){
pg.connect(conString, function(err, client) {
var horse = req.params.name;
var sql = "...";
client.query(sql, function(err, result) {
if (err) {
...
}
for (var i=0; i<result.rows.length; i++) {
// Customize data as needed
}
return res.send(JSON.stringify(result.rows));
});
});
});
Node is pretty low level. It's like C in JavaScript's clothing. Since it's comparable to C, there's pretty much a lot you can do with Node. Creating web servers is just one of them. You can create live chat servers using sockets, blogs, streaming etc. The possibilities are infinite. You are limited only by your imagination.
Routing is just a task where you take in commands (commonly via URL or headers) and do tasks based on those commands passed.
But even I have not yet scathed the surface of node. It's API is huge and getting bigger. Better try using some basic library like Express or Connect first since they pretty much abstract the basic requirement of building the server from code.

Categories