So I have a Node/Express server set up, and we are making the transition from subdirectories to sub domains for localisation, eg:
es.example.com // old way
www.example.com/es // new way
Doing this for a variety of reasons, but mostly to facilitate the preservation of JWT login state across the internationalised content. What is the best practice for allowing this in express when declaring routes?
If I have a route simply set up like this:
app.use('/search')
Then when I try to hit a route, eg www.example.com/es/search, I will just be redirected to www.example.com/search, the es will be stripped. However, this can be fixed like this:
app.use('*/search')
I'm sure this must have some negative implications though? How do people typically allow for prefixes in routes via Express?
If you are using Express 4, you can use modular routes to create a set of routes that can then be shared across your different locale codes. This will ensure that you only apply routes to specific locale codes rather than all possible words prior to your route (such as /fakePath/search).
// routes.js
var express = require('express');
var router = express.Router();
router.use('/search');
module.exports = router;
// index.js
var routes = require('./routes');
app.use('/en', routes);
app.use('/es', routes);
// ...
Related
I see these two lines in ( every ?) Express app.
const express = require('express');
const app = express();
I have to wonder if any parameters can be passed to express()?
Checked here and did not see any
https://expressjs.com/en/4x/api.html
Why are some methods on express() and some on app()?
It seems like they should be combined and have all methods on one object.
express does not take any parameters, no. The purpose of calling it is to create the app object, so the fact you have to call it does make sense, even without parameters.
Another way you often see that written is:
const app = require("express")();
It'll need to be separate again when using ESM, though.
import express from "express"; // Or similar
const app = express();
In a comment you've said:
For example, is there anything useful I can do with out creating app? Is there anything I can do only with express?
As far as I know, you have to have create at least one Application object to do anything useful with Express. Note that you don't have to create just one app. That's the typical use case, but there's no reason you can't create multiple apps running on different ports.
You may be wondering why express can't just give you an Application object directly from require. The reason is that modules are only loaded once and cached, so what you get from require is shared. So Express exports the express function, which you use to create the Application object (or objects, plural, if you want more than one).
Is there anything I can do only with express?
The reason for doing two separate lines like this:
const express = require('express');
const app = express();
instead of this:
const app = require('express')();
is that the express module has other methods on it that are sometimes needed such as:
express.static(...) // middleware for serving static files
express.json(...) // middleware for parsing json requests
express.urlencoded(...) // middleware for parsing urlencoded requests
express.Router(...) // constructor for a new Router object
In a recent learning project, I'm using three Express.js applications to separate the project into more manageable pieces.
One application is the "primary" app, the one that listens for connections. The other two are mounted at specific routes on the primary app.
Is it sufficient to call app.disable('x-powered-by'); on the primary app to disable the X-Powered-By header, or would this need to be done in each of the mounted apps as well?
Similarly, I'm looking into using Helmet.js to try and add a bit of additional security to the entire project. Is it enough to include any middleware from Helmet.js on the primary app, or would these also need to be defined in the mounted apps?
I don't feel as though I understand how some settings and middleware affect mounted Express.js apps, and would appreciate further explanation from anyone with more experience.
Edit: After playing with app.disable('x-powered-by') and examining responses from the server, the X-Powered-By header appears if I don't disable it in both the primary application instance and any mounted application instances. I therefore presume Helmet.js middleware operate the same way, but I'm not 100% certain. Can anyone confirm if this is the expected behavior?
You're right about everything you've said.
It sounds like you're doing something like this:
var express = require('express')
var mainApp = express()
var miniAppA = express()
var miniAppB = express()
mainApp.use('/a', miniAppA)
mainApp.use('/b', miniAppB)
mainApp.listen(3000)
This is an okay way to do things, but headers will be overridden in the sub-apps, as you saw.
You can use Express 4's routers feature to mitigate this. Instead of making new mini-apps with express(), you can use express.Router(). These are Express apps with fewer features (for example, they don't set headers the same way).
Something like this might solve your issue:
var express = require('express')
var mainApp = express()
var miniAppA = express.Router()
var miniAppB = express.Router()
mainApp.use('/a', miniAppA)
mainApp.use('/b', miniAppB)
mainApp.listen(3000)
I am developing a web application with the mean.js boilerplate code. Recently I added a view to my application (the 'analysis' page) by creating an analysis module and added some route logic with the following code.
//Setting up route
angular.module('analysis').config(['$stateProvider',
function($stateProvider) {
// Projects state routing
$stateProvider.
state('imageAnalysis', {
url: '/image_analysis',
templateUrl: 'modules/analysis/views/tools.client.view.html'
});
}
]);
This works just dandy, I can go to homepage.com/image_analysis and see my tools.client.view.html page. My goal now is to have this page only visible to user who are logged in. My first approach to this was to check if the user was logged in the angular routes logic, this has proven to be difficult for me. I also read that check authentication in the front end is very unsafe. So I've decided to check if the user is logged in with Express routing.
Here is an example of what Express routing looks like for one of my other AngularJS modules
module.exports = function(app) {
var users = require('../../app/controllers/users.server.controller');
var projects = require('../../app/controllers/projects.server.controller');
// Projects Routes
app.route('/projects')
.get(users.requiresLogin, projects.list)
.post(users.requiresLogin, projects.create);
app.route('/projects/:projectId')
.get(users.requiresLogin, projects.read)
.put(users.requiresLogin, projects.hasAuthorization, projects.update)
.delete(users.requiresLogin, projects.hasAuthorization, projects.delete);
// Finish by binding the Project middleware
app.param('projectId', projects.projectByID);
};
Notice the users.requiresLogin function which check if a user is logged in and redirects the user to the signin page if they are not. I want to take advantage of this function. Some things I dont quite understand in the boilerplate code are what is the purpose of app.route()? I think this might be a middleware but I am not sure what it does.
Here are some attempts I've take taken at messing around with express routing. These attempts are in my analysis.server.routes.js file that I created.
Attempt 1
module.exports = function(app) {
var users = require('../../app/controllers/users.server.controller');
// analysis routes
app.get('/image_analysis', function(req, res) {
console.log('helloworld');
console.log('helloworld');
console.log('helloworld');
console.log('helloworld');
console.log('helloworld');
console.log('helloworld');
});
};
I thought this would log 'helloworld' when I access the image_analysis page, but it didnt appear to do anything.
Attempt 2
module.exports = function(app) {
var users = require('../../app/controllers/users.server.controller');
// analysis routes
app.route('/image_analysis')
.get(users.requiresLogin);
};
Based on the other code, I thought this might work to require login for the analysis page. But it did nothing.
Any help would be much appreciated! Thanks everyone, I am struggling to grasp express routing at the moment and stackoverflow has been a tremendous help.
I don't have a solution, or not at least at this moment that I could think of.
However I can explain to you how things work and why a solution might not be trivial.
what is the purpose of app.route()
This defines your routes.
app.route('/projects/:projectId')
.get(users.requiresLogin, projects.read)
.put(users.requiresLogin, projects.hasAuthorization, projects.update)
.delete(users.requiresLogin, projects.hasAuthorization, projects.delete);
What that code does is when a client requests a URL like one of the following
GET /projects/5562ff08de4f70180bba3083
PUT /projects/5562ff08de4f70180bba3083
DELETE /projects/5562ff08de4f70180bba3083
it first executes that middleware function users.requiresLogin,
which is defined to be common in all methods (.get .put .delete)
and then their respective middlewares in that order
projects.read | projects.hasAuthorization ...
On how Angluar routing works in contrast to Express routing:
Angluar routing is all done client-side. It's all achieved through Javascript
changing the addressbar url and displaying the view attached to that route.
Your Angular app is served by the server through a single (Express) route - / (homepage)
So again, your entire Angular app loads thorough just 1 route on the server-side,
and then Angular takes over the routing to client-side through it's own ui-router.
Now it must be starting to seem obvious that it's not trivial to have server-side authentication check
interfere between client-side routing.
You can only have server-side authentication work with routes that server actually is in control of serving.
Those are mostly just your API routes, in your case.
Attempt 1
app.get('/image_analysis', function(req, res) {
console.log('helloworld');
I thought this would log 'helloworld' when I access the image_analysis page, but it didnt appear to do anything.
It indeed should have! Unless.. there's a route that comes before it that already serves all requests
app.get('*', function(req, res) {
res.send(angularApp); // your angular app is served here
});
// No request would *need* to go beyond past this point
// because it already got served above
app.get('/image_analysis', function(req, res) {
// so this isn't reached.
console.log('helloworld');
});
So that's why it doesn't work.
I am starting to learn Node.js, using Express with Jade and Mongoose as my default toolbox. I used to develop in PHP, migrated to Python, and learned MVC through Django. Having a large client-side JS game and some inspiration from Mozilla.org, I am willing to make a multiplayer game -- and saw this as a noncommercial opportunity to learn Node: I can take my time with it.
However, I ran into a problem. I'm not trying to write an MVC system on my own, just to separate my site's "apps" like most MVCs do. The question is probably basic -- having this chunk of code:
app.get(/^blog/, function(req, res) {
require("./blog")();
});
... I understand the basics of Node/Express' URL masking, however I need to pass the rest of the URL string (everything that's after mysite.com/blog) to another URL parsing script, inside the blogapp.
I googled around for a while and couldn't find a good solution. I even found a full tutorial on building an MVC scheme in Node and Express written for an older Express version, but that's a bit over the top for now. Can you provide me a simple solution?
I think blog/index.js should look something like this:
module.exports = function(urlstring) {
if(urlstring.indexOf('post') != -1) {
// do stuff...
}
else if(urlstring === '/') {
// return home.jade or something
}
};
I hope I'm being clear. Thanks in advance!
With express there is no need to parse your URLs on your own. I guess you'll want to build your blog URLs somehow like this
/blog Show a list of blog posts
/blog/post/1 Show blog post with id '1'
With express 4 you can set up a router for your blog path or a mounted app. Mounted apps allow you to let an app handle all sub URLs of a base URL path. See the express documentation for more detail.
I'd like to demonstrate how you can use the express 4 router together with the mounting feature of express to build blog routes.
// Set up express app
var app = express();
// Set up a router
var router = express.Router();
router.get('/', function(req, res) {
// Show a list of blog posts
}
router.get('/post/:id', function(req, res) {
// Show a single blog post
}
// Mount router
app.use('/blog', router);
A benefit of this solution is that your routes registered in the router always get relative URLs with out the /blog prefix so you may reuse your blog routes in some other project under a URL like /companyblog.
I'm using the vhost express/connect middleware and I'm a bit confused as to how it should be used. I want to have one set of routes apply to hosts with subdomains, and another set to apply for hosts without subdomains.
In my app.js file, I have
var app = express.createServer();
app.use...(middlware)...
app.use(express.vhost('*.host', require('./domain_routing')("yes")));
app.use(express.vhost('host', require('./domain_routing')("no")));
app.use...(middlware)...
app.listen(8000);
and then in domain_routing.js:
module.exports = function(subdomain){
var app = express.createServer();
require('./routes')(app, subdomain);
return app;
}
and then in routes.js I plan to run sets of routes, dependent on whether the subdomain variable passed in is "yes" or "no".
Am I on the right track or is this not how you use this middleware? I'm a bit confused on the fact that there are two app server instances being created (as that's how examples on the web seem to do things). Should I instead pass in the original app server instance and just use that instead of creating a separate one instead the subdomain router?
Yes, you are on the right track. You should have a different server instance for each of the vhost. Be it a http.Server or express app.
If you pass the original app, a request you sent to the vhost will be emitted to the original app. So, unless the vhost has paths which are not used in original server, it will get response as if the request was sent to original server.
From the connect docs
connect()
.use(connect.vhost('foo.com', fooApp))
.use(connect.vhost('bar.com', barApp))
.use(connect.vhost('*.com', mainApp))