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)
}
};
Related
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
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');
I want to completely dissociate my client app from Parse server, to ease the switch to other Baas/custom backend in the future. As such, all client request will point to a node.js server who will make the request to Parse on behalf of the user.
Client <--> Node.js Server <--> Parse Server
As such, I need the node.js server to be able to switch between users so I can keep the context of their authentification.
I know how to authentificate, then keep the sessionToken of the user, and I ve seen during my research than the "accepted" solution to this problem was to call Parse.User.disableUnsafeCurrentUser, then using Parse.User.become() to switch the current user to the one making a request.
But that feels hackish, and I m pretty sure it will, sooner or later, lead to a race condition where the current user is switched before the request is made to Parse.
Another solution I found was to not care about Parse.User, and use the masterKey to save everything by the server, but that would make the server responsible of the ACL.
Is there a way to make request from different user other than thoses two?
Any request to the backend (query.find(), object.save(), etc) takes an optional options parameter as the final argument. This lets you specify extra permissions levels, such as forcing the master key or using a specific session token.
If you have the session token, your server code can make a request on behalf of that user, preserving ACL permissions.
Let's assume you have a table of Item objects, where we rely on ACLs to ensure that a user can only retrieve his own Items. The following code would use an explicit session token and only return the Items the user can see:
// fetch items visible to the user associate with `token`
fetchItems(token) {
new Parse.Query('Item')
.find({ sessionToken: token })
.then((results) => {
// do something with the items
});
}
become() was really designed for the Parse Cloud Code environment, where each request lives in a sandbox, and you can rely on a global current user for each request. It doesn't really make sense in a Node.js app, and we'll probably deprecate it.
I recently wrote a NodeJS application and had the same problem. I found that the combination of Parse.User.disableUnsafeCurrentUser and Parse.User.become() was not only hackish, but also caused several other problems I wasn't able to anticipate.
So here's what I did: I used
Parse.Cloud.useMasterKey(); and then loaded the current user by session ID as if it was a regular user object. It looked something like this:
module.exports = function(req, res, next) {
var Parse = req.app.locals.parse, query;
res.locals.parse = Parse;
if (req.session.userid === undefined) {
res.locals.user = undefined;
return next();
}
Parse.Cloud.useMasterKey();
query = new Parse.Query(Parse.User);
query.equalTo("objectId", req.session.userid);
query.first().then(function(result) {
res.locals.user = result;
return next();
}, function(err) {
res.locals.user = undefined;
console.error("error recovering user " + req.session.userid);
return next();
});
};
This code can obviously be optimized, but you can see the general idea. Upside: It works! Downside: No more use of Parse.User.current(), and the need to take special care in the backend that no conditions occur where someone overwrites data without permission.
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);
I currently have an app which uses Express with Jade templates.
I'm building a new version of the app using Angular with client-side HTML.
I need access to certain request parameters in order to determine user permissions in my Angular code. My problem is that I don't know how to get ahold of these parameters in my Angular controllers/services.
Below is what currently occurs in Express with the Jade structure:
routes.js:
router.get('/player/:id',
playerRoute.show
);
player.js:
var show = function(req, res) {
res.render('player', {user: req.user});
};
...and now my new version's handler:
var player = function(req, res) {
//res.sendFile(path.join(__dirname, '../v2', 'index.html'));
res.json({user: req.user});
};
The correct user JSON is sent back to my client-side with the code above. When res.json is commented out and res.sendFile uncommented the correct HTML is rendered. My dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?
After all that, your question just boils down to:
MY dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?
You don't. The usual case is to just render the HTML along with the assets needed to render the initial app (hide everything, show a splash screen whatever). Further data (like getting your user) is handled by API calls to your server via Angular's HTTP facilities. That means they are separate. After that API call, your app determines what to render.
Otherwise, you could just render the data in the HTML as some global variable and have Angular pick it up from there. This is messy IMO, but doesn't require a separate API call to get the data.
copied from my own answer to a similar question
To get a variable from server to client javascript try templating a json string into the html and loading it from the javascript. EJS handles quote escaping and I think Jade does too. For reference content!= safeString tells Jade to skip escaping, so does content !{safeString}.
- var user={id:1, displayName:'foo'}
#example
meta(data-userJSON=JSON.stringify(user))
script(src="//code.jquery.com/jquery-1.11.3.min.js")
script.
var user = JSON.parse(
$('#example meta').attr('data-userJSON')
)
console.log(user);
span #{user.id}
span #{user.displayName}
Here's how I ended up handling this situation. I simply created a new API endpoint which I can easily hit with an Angular service. Here's the Node setup:
routes.js:
router.get('/currentUser',
apiController.currentUser.index
);
currentUser.js:
var index = function(req, res) {
res.json({user: req.user});
};
module.exports = {
index: index
};
Still seems odd to me to make an API call to get the request parameters, but it works. Feedback appreciated.