If I use express-session the session variable becomes available under req.session in for example:
app.get('/', function(req, res) {
req.session.myVar = 1;
}
But what if I want to retreive the session of the current request deeply nested in my application where I do not have the req variable available?
Is there another way besides passing in the req variable as a parameter all across the framework?
Is there another way besides passing in the req variable as a parameter all across the framework?
No, not really. A node.js server (that uses any asynchronous operations) can have multiple requests in flight at the same time. So, any request-specific data that you want to access has to come from an object that is associated with this particular request and only this specific request. You can't put it in globals because those can be intermixed from different requests. You have several options, but ultimately you have to pass the data through your functions to wherever it is needed -there is no shortcut here. Here are several options:
Put the data on req and pass req through your code to the function that needs the data.
Pass the data itself (no need to pass the whole req object if you only need once piece of data.
Create a new object that is specific to this particular request (not shared with other requests or available to other requests) and put the desired data as a property on that object and then pass that object through to the desired code. In an OO world, you can usually put multiple functions as methods on a shared object and then the data is automatically available to all those methods so you don't have to explicitly pass it.
Use a shared scope and closure so that any functions that need access to the data can get it directly from a parent scope.
The solution for me was to use Continuation-local-storage as middleware for express like outlined in this question as well NodeJS TransactionID with Continuation-local-storage
import * as cls from "continuation-local-storage";
cls.createNamespace('mynamespace');
app.use((req, res, next) => {
let session = cls.getNamespace('mynamespace');
session.bindEmitter(req);
session.bindEmitter(res);
session.run(function() {
session.set('req', req);
next();
});
});
and when you need it later on:
var session = cls.getNamespace('mynamespace');
var req = session.get('req');
Related
My current project is using Node for both frontend and backend and ExpressJS as the middleware.
I have a requirement where I need a feature toggling implementation to introduce some new features in my application. I am using a url parameter, e.g. &featureToggle=true to determine if the code of execution would be the new one or the existing.
Now I have parts in frontend and backend both which need to be changed based on the feature toggle. In the backend I can get the query object separately and extract the url param, similarly also in the frontend module.
Is there a way in which I can use Express to intercept the query param, set a variable value to either true or false based on the feature toggle, and which could be used across both the frontend and backend modules?
with express you can use req.query which gathers the query string sent in the request. You could pass it like this:
localhost:9000/path?&featureToggle=true
the ? is important it tells express that you are creating a query.
if you then place it into a variable:
const query = req.query
you would get the following output:
{ featureToggle: 'true' }
so as you can see it is returning an object.
you can check it like so:
if(req.query.featureToggle === 'true'){
runSomeCode();
};
or in your case if you want to run some kind of middleware:
router.get('/', (req, res, next) => {
if(req.query.featureToggle === 'true'){
return next(toggle)
}
};
Why is a URL that is recognizable to Express.js, not like the usual URLs we see?
For example:
Express.js will recognize this URL (http://localhost:3000/things/0) where id=0 if I make this GET request:
app.get('/things/:id', (req, res) => {
// Do somethihng
});
But this URL (http://localhost:3000/things/?id=0) which is more like the usual URLs we see won't work for the same GET request above.
So, "normal URLs" is apparently in the eye of the beholder as there are really just different styles, neither being any more normal than the other.
There are a couple ways to pass parameters in a URL.
#1 - You can embed it in the path of the URL
https://someserver/things/0
https://contacts.google.com/person/c3429579852656514228
This is referred to as a RESTFUL design. These URLs contain a noun and then an id that identifies which of those nouns the URL refers to.
#2 - You can put the variable part of the URL in a query parameter
For those same two URLs above, that could look like this:
https://someserver/things?id=0
https://contacts.google.com/person?id=c3429579852656514228
There are valid reasons for both designs depending upon circumstances and there are even cases where you combine the two (add optional query parameters to the restful API designs in option #1. Neither one is "normal" - they are different ways to design your URLs.
Express allows you to use either one. For restful parameters that are in the path of the URL, you use the :id syntax and you access the value in req.params.id:
app.get('/things/:id', (req, res) => {
console.log(req.params.id);
res.send(req.params.id);
});
For query parameters, you don't define them in the express route path. Instead, Express parses any query parameters that exist on any route and makes them available in req.query.
// expecting /things?id=789&sort=alpha
app.get('/things', (req, res) => {
console.log(req.query.id); // "789"
console.log(req.query.sort); // "alpha"
res.send(req.query.id);
});
Any query parameter that is present in the URL will be added to the req.query object.
Note that query parameters are often considered optional and thus you don't code them into your route definition. If you want to require a specific query parameter, then you have to check if it's there and, if not, then provide some error response or call next() to continue to routing to other request handlers.
FYI, there's another style that often uses client-side code to help build that page and puts URL arguments in a hash tag too, but I'll leave that for another day.
(http://localhost:3000/things/?id=0) which is more like the usual URLs
It's framework and it doesn't do what you and I think. It has set of rules.
Talking about best practices for RESTFUL API, design is that path params(/:id) are used to identify a specific resource or resources, while query parameters(?id) are used to sort/filter those resources. So, for /things/?id=0, We should use query parameters.
we see won't work for the same GET request above.
It will not work that way. In order to get query parameters use something like
app.get('/things', (req, res) => {
let id = req.query.id;
// here you can get id.
});
QUERY PARAMETERS:
How to get GET (query string) variables in Express.js on Node.js?
ABOUT URL: https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_is_a_URL
I am a web developer with a PHP background that moved recently to JS.
In PHP, we used to have the $_SESSION global variable which make your session variables accessible from any 'place' in your code (Great feature!).
Now, working with an ExpressJS application, I am using express-session package to create session variables.
The issue is that session variables in ExpressJS are NOT global, they are property of the request object (req.session). So they are only accessible in functions that have a req parameter (AKA middlewares and route functions).
The question is: Is it possible to make session variables in ExpressJS global ala PHP, so any 'helper' function can handle them?
Yes, but you should not do that. You can create globals by appending properties to the global object. For example: global.someData = req.session.someData, but the global object is similar to the GLOBAL from PHP.
In that case, especially if you have async functions, the variables of one request will mess up with the code running for another request (e.g. Alice would get the Bob's variables).
The good practice is to pass the req.session object wherever that is needed and access it.
You can use CLS (Continuation-local-storage) to achieve this.
All you have to do is create a namespace and bind it to each request.
Now, add the below code to your server.js where you initialize your server
//server.js
var express = require('express');
var app = express();
var createNameSpace = require('continuation-local-storage').createNamespace;
var myNameSpace = createNameSpace('myNameSpace');
// Assign your sessionVariable to each request as 'sessionId'
app.use(function(req, res, next) {
myNameSpace.run(function() {
myNameSpace.set('sessionId', sessionVariable);
next();
});
});
Add the following code anywhere in you application to access your sessionVariable
var getNamespace = require('continuation-local-storage').getNamespace;
var myNameSpace = getNamespace('myNameSpace');
var sessionId = myNameSpace.get('sessionId'); // access your sessionId (sessionVariable)
Note that using CLS can be tricky sometimes.
Once your session variable is setup (either on your login function or wherever you are setting it up) it is then a global variable on your index.js file.
I setup my session like so:
var students = {Id: result[key].Id,Username: result[key].Username,Email: result[key].Email,Phone: result[key].Phone,First_Name: result[key].First_Name,Surname: result[key].Surname,RoleName: result[key].RoleName, Company: result[key].CompanyName };
Users.push(students);
req.session.user = students;
You can access the stored session by setting up a var like the below:
var session = req.session.user
This will set the session to a session variable where you need it inside your function.
Then when you render a page you just need to add the session to that render and you will have access to it on that page.
res.render('/', { title: 'Hello World', session: session});
I've built a very simple translation module for Express JS, it's a global object in the application scope that's instantiated at application runtime:
translator.configure({
translations: 'translations.json'
});
I've added some simple middleware to Express JS that changes the locale in the translator module for each request:
app.use(function(req, res, next) {
var locale = // Get locale from request host header
// Setup the translator
translator.setLocale(locale);
// Attach translator to request parameters
res.locals.__ = translator.translations;
// Pass control to the next middleware function
next();
});
Then I access my translations through the variable __ in my views (here I use ejs):
...
Here is my translated text: <%= __['test'] %>
...
My translator module looks like this:
var translations,
locale;
// public exports
var translator = exports;
translator.configure = function(opt) {
translations = require('./' + opt.translations);
};
translator.setLocale = function(locale) {
translator.translations = translations[locale];
}
The translations.json file is just a simple JSON structure:
{
"us":{
"test": "Hello!"
},
"es":{
"test": "Hola!"
}
}
My question is, is this overall structure a bad idea? I do not have extensive knowledge about express JS. The global object makes me kind of nervous since the translations are based of its current state, which is changed from request to request, any problems here? Does express JS fully complete a request before handling the next one, or is there some level of concurrency going on that can mess up my translations?
A global object is a bad idea for saving state that is used during a request. A request is not necessarily completed before the next one starts running. If, at any time, a request handler makes an asynchronous call (like to read a file), then another request can start running at that point.
In general, you should store state related to a specific request on the request object itself. That way, it is not global and is stored specifically for that request only and you can have as many requests going at once without conflict.
So, you could ideally not store any request-specific state in your translator object at all unless you create a new translator object for each request and then store that specific translator object in the request object.
I don't follow your translator code exactly, but this looks like trouble:
app.use(function(req, res, next) {
var locale = // Get locale from request host header
// Setup the translator
translator.setLocale(locale);
// Attach translator to request parameters
res.locals.__ = translator.translations;
// Pass control to the next middleware function
next();
});
Because it looks like you're configuring a shared, global translator object, then expecting to use it later and expecting it not to be changed by any other request. That seems like asking for trouble.
If your request handler makes any async call at any point, then another request handler can run which can create a conflict as both try to use the same translator object.
I understand that out of the box Express isn't an MVC framework, however I'm trying to set it up like one.
I've used other similar frameworks in PHP like Laravel where in a route in you can use a controller like
Route::get('user/profile', 'UserController#showProfile');
Which will run all the code in the showProfile method in the UserController class,
so my question is, how would I achieve the same thing or something similar using Express?
I'm using Node 5 and writing the code in ECMAScript 6.
Currently I have a class I want to use as the controller and a method I want to return the data, I'm able to log the data to the console when a user navigates to the route but haven't figured out how to send it back as the response.
If you dive into the documentation, you'll find that the "controller methods" you refer to need to conform to a specific signature. Namely, they receive (at least) the request and response representations.
If you have already created a router, this will be a rough equivalent to the PHP you posted:
router.get('user/profile', userController.showProfile)
Your showProfile "method" needs to have this signature:
const userController = {
showProfile(req, res) { /*...*/}
}
I put "method" in quotes because express won't call it as a method unless you explicitly bind it to the controller object. We're passing it as an unbound function here. If you wanted to use it as a method (to have access to the controller as this), pass userController.showProfile.bind(userController) to router.get†.
But for now let's stick to those req and res parameters of the showProfile handler (that's the proper name). req represents the HTTP request, you can get headers, request payload and other stuff from it. res is the HTTP response that will be sent. So you can use it to set an HTTP status code, send body data and so on.
For illustrative purposes, let's assume you can get your user profile synchronously by calling userController.getProfile(id). And let's assume that, by some mechanism, a property userId is set on the request that is the currently authenticated user's ID.
const userController = {
showProfile(req, res) {
// We call some code to get what we want to send back
const profile = userController.getProfile(req.userId)
// We send it in the response as JSON
res.send(profile)
}
}
res.json will JSON.stringify the profile and send it as response payload.
How do you get req.userId set, you ask? Well, this is just an example, but you can achieve similar results by using middleware. A middleware is simply a handler that does something and then lets other handlers continue processing the request. But again, there's plenty to read from the docs.
† It's usually not necessary though, since controllers tend to be singletons. You can simply access its properties by doing userController.otherProperty. Of course, you don't even need to define a handler as a method of a controller object, it can be a function that stands on its own.
I did something like this
usercontroller.js
class UserController() {
constructor() {
this.users = ['user1', 'user2'];
}
getUsers(req, res) {
res.status(200).json(this.users);
}
}
//router.js
const port = 3000;
const app = express();
const _invoke = function(controller) {
return function(req, res) {
const [controllerClass, method] = controller.split('#')
const className = require(controllerClass)
const obj = new className
obj[method](req, res)
}
}
app.get('/get-users',
_invoke('./controllers/UserController#getUsers'));
app.listen(port);