Express Routes & Controllers - javascript

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);

Related

Parsing Body from request to Class in express

I got doubt, im coming from .net with c# and i want to parse my body request as .net does for my automatically, how can i set a class or an interface as a request body in express, i have found many options but all of them just destruct the body into the properties that they need, i need a way or a method that allows me to get only the properties that i specified in my class.
In .Net it will be something like this.
[HttpGet("someName")
Public IActionResult GetSomething(Myclass instance){
// the instance with only the properties that i specified in my class and not the hole body with useless props that i don’t request
instance.someProperty
Return Ok()
}
ASP.net is actually smart enough to understand that when a class is declared as an argument, it must map from the request POST body to the class.
Nodejs and express do not always come with batteries included.
You need to add a middleware that can read the raw request and get the json object you want. If you are only receiving JSON then you need the JSON middleware. If you expect to have URL encoded posts (for file uploading or html s) then you also need to add the urlencoded middleware
const app: Application = express();
(...)
app.use(express.json());
app.use(express.urlencoded());
At this point, you can declare your route, and express will corectly fill the req.body object with your post data.
interface MyPostBody {
foo: string;
bar: string;
}
app.post("/api/someName", (req, res) => {
const instance = req.body as MyPostBody;
console.log(instance.foo);
console.log(instance.bar);
const result = doSomething(instance);
res.send(result);
});
Please be aware that we are just casting the type here, so if your client sends an object that does not conform to the MyPostBody interface, things will break. You probably need to add some validation to ensure the data conforms to you api contract. You can use some validation library like yup for that. To keep it simple I will do something very basic here.
app.post("/api/someName", (req, res) => {
if(req.body.foo === null || req.body.foo === undefined) {
res.status(400).send("foo is required");
return;
}
if(req.body.bar === null || req.body.bar === undefined) {
res.status(400).send("bar is required");
return;
}
const instance = req.body as MyPostBody;
console.log(instance.foo);
console.log(instance.bar);
const result = doSomething(instance);
res.send(result);
});

Feature toggling using Expressjs middleware - frontend and backend

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)
}
};

Retreive session information in nodejs / express without request variable

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');

Using a global translation object in express JS

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.

Sailsjs: Setting response method based on request parameter

So I have been working on a SPA project using Sailsjs. The problem is:
When the first page loads, I use res.view or res.render in my controller. But, for subsequent requests, I dont want to use res.view or res.render, rather I'd like to use res.json.
Right now, I use the method:
return req.param('json') ? res.json(myObj) : res.view('layout', myObj);
This works, but I was looking for a more generic and abstract method in which my controller itself would know (on the basis of req.param('json')) whether to use res.view or res.json without me having to tell it explicitly.
Any help ?
This is what res.ok() is for.
In the controller action below, res.ok will either display the myAction.ejs using data as the view locals, or respond with data as JSON, depending on how the request came in (i.e. via AJAX, sockets or a regular browser request):
module.exports = {
myAction: function(req, res) {
var data = {someKey: "someVal"};
return res.ok(data);
}
}
Internally, the ok response uses req.wantsJSON to determine what to do; it checks headers, looks for an xhr object and generally does its best to guess your intent. req.wantsJSON is available for all requests (as is req.isSocket), so you can use them yourself as needed.
So after a bit of tinkering, I resolved this using a service.
I wrote a service (in GlobalUtils.js):
render: function (req, res, obj) {
if(req.param('json')) {
return res.json(obj);
}
else {
return res.view('layout', obj);
}
}
And I use this service in my controllers, like so:
return GlobalUtils.render(req, res, myObj);
But still, looking for a better method.

Categories

Resources