How can I change the express static path based on the route? - javascript

I want to change the static path based on the route. For example (not working):
const app = express();
const appRouter = express.Router();
const adminRouter = express.Router();
appRouter.use(express.static('/path/to/app/static/assets');
adminRouter.use(express.static('/path/to/admin/static/assets');
app.use('/', appRouter);
app.use('/admin', adminRouter);
This also does not work:
const app = express();
app.use('/', express.static('/path/to/app/static/assets');
app.use('/admin', express.static('/path/to/admin/static/assets');
What I do not want to do is set both paths as static for the entire app:
// the following will expose both paths as static for the entire app
// this does not accomplish what I am trying to do
const app = express();
app.use(express.static('/path/to/app/static/assets');
app.use(express.static('/path/to/admin/static/assets');
Is this possible?

What you are trying to accomplish is not possible from your approach with express.static(). Your #2 approach does create virtual path prefix (where the path does not actually exist in the file system) for files that are served by the express.static function. Follow this for more info.
But what seems can be done is changing the path of express.static() in run time. Please follow through this git issue. Hope it helps.

I don't think it is possible with Express static middleware.

I was able to come up with a solution following the git issue posted by Tolsee. I published it to npm under the name express-dynamic-static.
Here is quick example of how to use it:
const express = require('express');
const dynamicStatic = require('express-dynamic-static')(); // immediate initialization
const path = require('path');
const app = express();
app.use(dynamicStatic);
app.get('/', (req, res) => {
dynamicStatic.setPath(path.resolve(__dirname, 'path/to/app/assets'));
// res.render...
}
app.get('/admin', (req, res) => {
dynamicStatic.setPath(path.resolve(__dirname, 'path/to/admin/assets'));
// res.render...
}

Related

Why not using "require('express')()"

To create a simple Web server with NodeJS and Express, all the tutorials giving examples like this
const express = require('express');
const app = express();
app.listen(3000, () => console.log("Started"))
app.get('/', (req, res) =>{
res.send("Yaaa")
})
My question is, Why not write it like this?
const app = require('express')();
app.listen(3000, () => console.log("Started"))
app.get('/', (req, res) =>{
res.send("Yaaa")
})
The only difference is merging lines 1 and 2, as far as I'm not going to use/need the "express" constant anymore.
Is that wrong? And why?
As far as I know about express framework. Express exposes us to a lot of useful functions. If we don't require or import express in our application then, Our application will not be able to use those functions.
For example if you are creating some REST APIs then, We need our APIs to take form-data or raw as input. If we want to allow our application to take raw-json as input then, we need to add a middleware which consumes a built-in express function.
app.use(express.json())
If you want create an application that has a seperate folder for all the routes. Then, we use express.Routes() for that. That's how we create routes file in seperate routes folder:
import express from 'express';
import userController from 'path/to/user/controller';
const router = express.Router();
router.post('/follow/:userid/:following', helper.verifyToken, userController.follow);
router.get('/someRoute', userController.someAction);
export default router;
Similarly, If we want to serve some static HTML or some react-build. Then, we use express.static() inside app.use() middleware like this:
app.use(express.static('/path/to/static/folder'));
As long as you don't need access to the express module elsewhere in this file, then doing:
const app = require('express')();
is the best way.
But if we require to use to this express module again and again. Such as below
const app = require('express')();
const friendsRouter = require('express').Router();
Then it becomes a problem and you have require it again and again.
So to make our code less redundant, we use normal given approach. As in below code:
const express = require('express');
const app = express();
const friendRouter = express.Router();

express-subdomain handling any subdomain

I'm trying to use https://github.com/bmullan91/express-subdomain for subdomain routing in express. The following are the contents of my main.js and src/routes/site files.
const express = require('express');
const bodyParser = require('body-parser');
const subdomain = require('express-subdomain');
const siteRouter = require('./src/routes/site');
const app = express()
app.use(express.json() );
app.use(express.urlencoded());
app.use(express.static('public'));
app.use(subdomain('*.www', siteRouter));
app.get('/', function(req, res) {
res.send('Homepage');
});
const server = app.listen(80,'x3.loc', function () {
var host = server.address().address;
var port = server.address().port;
console.log('X3 listening at http://%s:%s', host, port);
});
const express = require('express');
let router = express.Router();
router.get('/', function(req, res) {
res.send('Welcome to site');
});
module.exports = router;
This way of doing app.use(subdomain('*.www', siteRouter)); has been suggested in https://github.com/bmullan91/express-subdomain/issues/33 but does not work.
I have also tried just * as the subdomain aswell, but that caused the homepage w/o a subdomain, to get treated like one aswell. How could I get this to work?
We know that / matches any base path regardless of subdomain. So I made your homepage middleware "subdomain-aware" like so:
app.get('/', function(req, res,next) {
/* If there are any subdomains, skip to next handler, since request is not for the main home page */
if (req.subdomains.length > 0) {
return next();
}
res.send('Homepage');
});
Then I placed the middleware for subdomains below the homepage middleware like so:
app.use(subdomain('*', siteRouter));
This makes homepage middleware to serve requests for x3.loc and the subdomain middleware to serve requests for any subdomain like api.x3.loc or api.v1.x3.loc.
But in my opinion, the real fix should be done in the module. I think it should be changed so that either the case where req.subdomains being empty is handled, or * is matched against an actual string, instead of skipping the iteration.
I am surprised that the fix suggested in bug 33 worked as-is for the reporter. In my testing, it works the opposite way i.e. www.example.com goes to subdomain middleware while stat1.example.com goes to the homepage middleware. Perhaps the reporter saw this and swapped the middleware bodies.

NodeJS Express defining custom routes

This is probably a really basic concept that I'm not understanding but in my NodeJS application I am trying to define a custom route.
my directory structure is as follows
/application
/app.js
/package.json
/node_modules
/public
/routes
/control
/users.js
/views
/control
/users.ejs
Which I am happy with because I want to keep the routes and views in a 1 to 1 relationship because I will eventually end up with something like
/application
/app.js
/package.json
/node_modules
/public
/routes
/control
/users.js
/system.js
/tools
/stock.js
/report.js
/views
/control
/users.ejs
/system.ejs
/tools
/stock.ejs
/report.ejs
So I don't want to end up with a /routes/index.js file with a hideous amount of routing code inside.
It seems to work while my app.js file is as follows
//==============================================================================
// setup
//==============================================================================
var express = require("express");
var path = require("path");
var app = express();
var port = 3000;
var message = null;
app.set("view engine", "ejs");
app.use(express.static(path.join(__dirname, "public")));
//==============================================================================
// routes
//==============================================================================
var users = require("./routes/control/users");
app.get("/", users.users);
//==============================================================================
// start server
//==============================================================================
app.listen(port, function() {
message = "Server Started : Port " + port;
console.log(message);
});
Although I can see this is going to end up looking like
//==============================================================================
// setup
//==============================================================================
var express = require("express");
var path = require("path");
var app = express();
var port = 3000;
var message = null;
app.set("view engine", "ejs");
app.use(express.static(path.join(__dirname, "public")));
//==============================================================================
// routes
//==============================================================================
// control
var users = require("./routes/control/users");
app.get("/", users.users);
var system = require("./routes/control/system");
app.get("/", system.system);
// tools
var stock = require("./routes/tools/stock");
app.get("/", stock.stock);
var report = require("./routes/tools/report");
app.get("/", report.report);
//==============================================================================
// start server
//==============================================================================
app.listen(port, function() {
message = "Server Started : Port " + port;
console.log(message);
});
So I don't really want to have that many requires but doing it like the following doesn't seem to work and I'm not sure why
// control
var control = require("./routes/control");
app.get("/", control.users.users);
app.get("/", control.system.system);
// tools
var tools = require("./routes/tools");
app.get("/", tools.stock.stock);
app.get("/", tools.report.report);
You can use the express Router object to chain your routes. Here's an example
/app.js
var routes = require('./routes/index');
// as noted by Paul in the comments,
// you could use `app.use(routes)` for simplicity
app.use('/', routes);
/routes/index.js
var routes = require('express').Router();
routes.route('/test')
.get(function (req, res) {
res.send(req.originalUrl);
});
routes.use('/control', require('./control/user'));
module.exports = routes;
/routes/control/user.js
var routes = require('express').Router();
routes.route('/test')
.get(function (req, res) {
res.send(req.originalUrl);
});
module.exports = routes;
So for the route defined in index.js, you'll need to send a GET request to /test while in user.js, you will need to send a GET request to /control/test to get a response.
This way all you need to include in the main js file, app.js in your case, is the main routes file, which is index.js under the routes directory. Either way, you will still need to do one require statement for each file that exports a router object.
When you say:
var control = require("./routes/control");
Node will do the followings:
Since you privided a relative path to require, it will search for a routes directory within the current folder and in that directory search for a control.js file. It can't find control.js file so then:
Search for a control.json file. but it also can't find that
file. then:
Search for a control directory. It finds such a directory. opens
it and search for a package.json file to look into its
main property. but it also cant find such a file. then:
Search for a index.js file but also there is no such a file
By default when you give a folder path to require, it does not load .js files inside that folder automatically it looks for package.json file and if it's not there it loads index.js. i. e. It looks for an entry point.
So make an index.js in your control folder:
/routes
/control
/users.js
/system.js
/index.js
index.js:
module.exports = {
users: require('./users');
system: require('./system');
};
Do this also for your tools directory and your last approach should work.
Note that you could consider using express.Router to manage routes.

Node.js and dependecies management

Here is what i'm concerned about:
I'm writing a webapp in Node.js using express 4.
The question is for managing dependecies in all the code, but let me show you an example. I'm managing dependencies like this:
server.js:
var express = require('express');
var app = express();
app.use('/auth', require('./routes/auth'));
app.use('/profile', require('./routes/profile'));
routes/auth.js:
var express = require('express');
var router = express.Router();
// add routes to router
module.exports = router;
routes/profile.js:
var express = require('express');
var router = express.Router();
// add routes to router
module.exports = router;
How you can see, i'm importing express every time i need it in every module. I'm showing you the example with express, but i'm doing it with others modules.
Makes it better if i manage dependencies like this?
server.js:
var express = require('express');
var app = express();
app.use('/auth', require('./routes/auth')(express));
app.use('/profile', require('./routes/profile')(express));
routes/auth.js:
module.exports = function (express) {
router = express.Router();
// add routes to router
return router;
}
routes/profile.js:
module.exports = function (express) {
router = express.Router();
// add routes to router
return router;
}
I have to admit that my doubts are due to my lack of knowledge about Javascript and Node.js and my background with Python, where we do like the first form.
Any advice would be appreciated.
There is no real difference in performance, since Node.js' require caches every module on first call. However, the second approach has the benefits of explicit dependency injection, i.E. you could test every module in higher isolation by providing a mocked version of express. Plus you are ready for providing further dependencies like configuration or database objects.

How to mount app.get() routes on a particular path prefix

I'm writing an API using Node.js and Express. My API has GET methods of the form:
/api/v1/doSomething
/api/v1/doSomethingElse
My code is looking something like this:
server.js:
var app = express();
...
var routes = require('./routes')
routes.attachHandlers(app, '/api/v1')
routes/index.js
...
module.exports.attachHandlers = function(app, context) {
//get a list of all the other .js files in routes
//for each route, require() it and call it myRoute
myRoute.attachHandlers(app, context)
}
routes/some-route.js
...
module.exports.attachHandlers = function(app, context) {
app.get(context + '/doSomething', doSomething)
app.get(context + '/doSomethingElse', doSomethingElse)
}
...
Effectively I'm passing the context path/mount point down through the app. If somebody were to write a route like the following, though, the context would be lost:
app.get('/doFoo', foo)
Rather than having that part of the API mounted on /api/v1/doFoo it's on /doFoo. I would like to avoid having to pass the context path around like this.
app.use supports mounting middleware on an optional mount path. I have seen references online to mounting an entire Express application on a mount path using app.use. This seems like the sort of thing I want to do, but I'm not sure how to do it or if it's the best solution for my particular use case.
To summarise - I want to mount my app.get() routes with a particular prefix by default. What's the best way of doing this?
With Express 4.0, the task is much cleaner with the Router. You can create as many routers as you need to nicely partition your app, and then attached them with app.use(). For example:
myapp.js
var express = require("express"),
router = express.Router(),
app = express(),
port = 4000;
// Here we declare our API which will be visible under prefix path
router.get('/', function (req, res) {
console.log("request to subspace hello");
res.send({ message: "Hi from subspace /api/v1/"});
});
// we attach our routes under /api/v1
app.use('/api/v1', router);
// here we have direct, root-level routing
app.get('/', function (req, res) {
console.log("request to rootspace hello");
res.send({message: "Hi from root /"});
});
app.listen(port);
console.log("App active on localhost:" + port);
Then run
node myapp.js
and visit
http://localhost:4000 and http://localhost:4000/api/v1
Here's a working example of mounting a route in Express 3:
./snipe3app.js
var express = require('express');
var app = module.exports = express();
app.get('/subapp', function (req, res) {
res.send('You are on the /sub/subapp page.');
});
./app.js
var express = require('express'),
http = require('http'),
subApp = require('./snipe3app'),
app = express();
app.use(express.favicon());
app.use(express.bodyParser());
app.use(app.router);
app.use('/sub', subApp);
app.get('/', function (req, res) {
res.send('You are on the root page');
});
http.createServer(app).listen(3000, function(){
console.log('Express server listening on port 3000. Point browser to route /secure');
});
You have to pay attention to the order in which the routes are handled when doing this.
I think express-namespace will work for this.

Categories