Express sub-apps not working - javascript

I'm trying to make my main app be able to dynamically add other sub-apps so that I can do something like '/user/appName' where appName is the name of the sub-app. In my project directory I have an 'apps' directory that will contain all the sub-apps (they will all have their own app.js). I made a simple function to do this and it works if I comment out all the error handling stuff. However, I would still like to use error handling.
I call the useApp function from a post method in the main app.
I've search and tried many things, but can't find anything where someone is trying to do something similar. Maybe I'm going about this the wrong way?
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes');
var login = require('./routes/login');
var user = require('./routes/user');
var admin = require('./routes/administrator');
var networkView = require('./routes/networkView');
var app = express();
//view engine setup
app.set('views', path.join(__dirname, 'views'));
/** if you want hogan to use ".html" file extension
app.engine('html', require('hjs').renderFile);
app.set('view engine', 'html');
**/
app.set('view engine', 'hjs');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/login', login);
app.use('/user', user);
app.use('/admin', admin);
app.use('/networkView', networkView);
// import a sub app
function useApp(appName) {
app.use('/user/' + appName, require('./apps/' + appName + '/app'));
}
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
exports.useApp = useApp;
module.exports = app;

I did some research on how express works. The problem is that the app.use() in my function adds the route to the end of the stack. And therefore is not reachable. I came up with the following solution:
/**
* function that allows sub apps to be added to this app dynamically (when the server is running)
* #param appName
*/
function useApp(appName) {
// add the route
app.use('/user/' + appName, require('./apps/' + appName + '/app'));
// put the new route before the 404 catch on the router stack
// this assumes there are 3 other routes after this one (len - 4)
var last = app._router.stack[app._router.stack.length - 1];
delete app._router.stack[app._router.stack.length - 1];
app._router.stack.splice(app._router.stack.length - 4, 0, last);
}
It moves the new route in the proper location in the stack, so it becomes reachable.
Not sure if it's the best approach, but it works.

I've built something to accomplish just that. Feel free to take a look:
https://github.com/tkiddle/expressPlate/tree/tkiddle
Make sure you're on the "tkiddle" branch.

Related

Node sub-route returning 404

I have just started using node.js with the Express framework, and I am trying to understand how the built in routing works. I have found that a "main" router can be defined from which other "sub-routes" are used. For now, my app initially makes a get request that loads a dropdown from a MySQL database. I added a demo button that should take the value in the dropdown and make a request with it as a query parameter to my sub-route. When the button is clicked for the sub-route, I am getting a 404. My app.js:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
My index.js (main route):
var express = require('express');
var router = express.Router();
var models = require('../models');
router.use('/savings', require('./savings.js'));
/* GET home page with locations and their initial data collection dates */
router.get('/', function(req, res, next) {
models.Location.findAll({
attributes: ['locationName', 'initializationDate']
}).then(function(locations) {
res.render('index', {
title: 'Solar Data Savings',
locations: locations
});
});
});
module.exports = router;
savings.js (sub-route):
var express = require('express');
var router = express.Router();
var models = require('../models');
/* GET calculate solar data savings and reroute */
router.get('/savings', function(req, res, next) {
req.param('locationID');
models.Bank.findAll({
attributes: ['bankID'],
include: [{
model: Location,
where: { locationID: Sequelize.col('bank.locationID') }
}]
}).then(function(banks) {
res.render('index', {
title: 'Solar Data Savings',
banks: banks
});
});
});
module.exports = router;
index.pug:
extends layout
block content
div(class="container-fluid")
h1= title
p This is the #{title} project website
form(action="/savings")
div(class="form-group")
label(for="locations")
div(class="col-sm-4")
select(id="locations" class="form-control")
-for(var i = 0; i < locations.length; i++) {
option(value="#{locations[i].dataValues.locationID") #{locations[i].getLocationName()}
-}
div(class="col-sm-4")
input(type="submit", value="Get Bank")
I believe I am misunderstanding a nuance to routing, and I've scoured the web for a solution to this particular problem with no luck. Help greatly appreciated
Your savings route on the server is set to /savings/savings whereas your form is calling /savings. Either change the form or change the server side:
In savings.js, change
router.get('/savings', function(req....
to
router.get('/', function(req....
Also, you are using get to submit a form. Maybe you need to change that to
router.post('/', function(req...
Just make following changes in index.pug :
extends layout
block content
div(class="container-fluid")
h1= title
p This is the #{title} project website
form(action="/savings/savings")
div(class="form-group")
label(for="locations")
div(class="col-sm-4")
select(id="locations" class="form-control")
-for(var i = 0; i < locations.length; i++) {
option(value="#{locations[i].dataValues.locationID") #{locations[i].getLocationName()}
-}
div(class="col-sm-4")
input(type="submit", value="Get Bank")
Actually your routing is wrong:
Currently you're calling as : your_url:port/savings
BUT Should be : your_url:port/savings/savings
LINE NEEDS CORRECTION
FROM : form(action="/savings")
TO : form(action="/savings/savings")

Express Error: TypeError: Router.use() requires middleware function but got a Object

I am creating an upload/download app, i don't know why its only my app.js file is having this problem. I searched all other answers on the internet but still it did not solve the problem.
here is the code below:
var express = require('express');
var path = require('path'); // add path to set and get
var fs = require('fs'); // add filesystem
var connect = require('connect');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var connect = require('connect');
var http = require('http');
var routes = require('./routes/index');
var users = require('./routes/users');
//var upload = require('./routes/upload');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static('public'));
app.use(express.static('files'));
app.use('/', routes);
app.use('/users', users);
//app.use('/upload',upload);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
Thanks for your help.
check in your all files
make sure you don't miss export it
module.exports = router;
Router.use() at all times requires a Middleware function as an argument. Assuming your route to download some files from your server, it should Look similar to this.
var Router = express.Router();
function downloadFiles(request,response) {
// some code to dowload files
}
// The above function which takes request and response
// should be passed to Router.use()
Router.use(downloadFiles);
When you that error it means that what you passed to Router.use() is not a middleware function like downloadFiles.

Angular2 Routing in conjunction to Express routing?

My angular2 app's routes don't work when accessed via URL... Express is rendering an error page instead.
So I have one route (/docs) which serves some static content and some other static resources, however, / is routed to an index.html which is managed by angular 2. So by opening the application root and then clicking various router links I can get to a route e.g. /tutorial/chapter/1. However, as that isn't a registered route in my express app, if I refresh the page I get a 404.
I want to be able to type http://localhost:3000/tutorial/chapter/1 into my browser and get that page. How do I set express to route all undefined routes to angular, and let angular handle the 404?
Here is my app.js:
var app = express();
// html view engine setup
app.set('views', path.join(__dirname, '/ng2/views'));
app.engine('html', require('jade').renderFile);
app.set('view engine', 'html');
app.use(express.static('ng2/views'));
app.use(express.static('ng2/public'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));
// uncomment after placing your favicon in /public
app.use(favicon(path.join(__dirname, 'ng2/public', 'favicon.png')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
//all static assetes for hexo content
app.use('/docs', serveStatic('features/docs/public', { 'index': ['index.html', 'index.htm'] }));
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
module.exports = app;
You can see the full repo here
Here is the routes middleware def:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
Angular 2 assumes that independent of the request URL, the frontend will be returned. This assumption is based on a feature modern browsers implement called push state. You have 3 options if you want to support anything but the bleeding edge of browsers:
Recommended: Seperate the API server from the client.
If you put your client on example.org and your express backend on api.example.org you can just do what Angular assumes to be true. You can also deploy independently and the client can live on a static host or CDN. This will require that you setup CORS though.
Catch-All Express Route
Make sure all your routes in Express differ from the ones you setup in NG2 and make a catch-all handler. Put something like this at the end of your routes/middleware but before the 404 handler!
app.use(function(req, res, next) {
res.sendFile("index.html");
})
Use legacy browser-url-styles for the router.
You can make the NG2 router use hashes for routes. Check here.
app.js
Since order is important and new code is inserted in multiple locations, the whole file is included. Look for comment started with // JS -
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var serveStatic = require('serve-static')
var file = require('./features/prepareTutorial');
var routes = require('./ng2/routes/index');
var app = express();
// html view engine setup
app.set('views', path.join(__dirname, '/ng2/views'));
app.engine('html', require('jade').renderFile);
app.set('view engine', 'html');
app.use(express.static('ng2/views'));
app.use(express.static('ng2/public'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));
app.use('/persist', express.static(__dirname + '/persist'));
// JS - Add /app
app.use('/app', express.static(__dirname + '/ng2/views/app'));
// I have to comment this line because it failed
//file.processTutorial(); //generate html rendered patches for tutorial steps
//file.genGit(); //generate git SHA
file.processChapters();
// uncomment after placing your favicon in /public
app.use(favicon(path.join(__dirname, 'ng2/public', 'favicon.png')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
//all static assetes for hexo content
app.use('/docs', serveStatic('features/docs/public', { 'index': ['index.html', 'index.htm'] }));
//app.use(subdomain('docs', express.static('docs/public')));
app.use('/script', serveStatic('features/docs/public/script'));
app.use('/style', serveStatic('features/docs/public/style'));
app.use('/images', serveStatic('features/docs/public/images'));
app.use('/diff', serveStatic('features/tutorial/diffs'));
app.use('/git', serveStatic('features/git'));
app.use('/chapter', serveStatic('ng2/views/app/tutorial/chapter/chapters'));
app.use('/img', serveStatic('features/docs/source/img'));
app.use('/config', serveStatic('ng2/config'));
app.use('/', routes);
// JS - /tutorial static
//app.use('/tutorial', express.static('ng2/views/app/tutorial'));
// JS - /tutorial/chapter/* send index file
app.all(/^\/tutorial$/, (req, res) => {
res.redirect('/tutorial/');
});
app.use('/tutorial/', (req, res) => {
res.sendFile(__dirname + '/ng2/views/index.html');
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
ng2/config/systemjs.config.js & ng2/public/config/systemjs.config.js
Use absolute path
This is the main issue. With relative path, the browser is requesting files at tutorial/chapter/2/app/*, tutorial/chapter/2/node_modules/*, etc, and the app break down completely.
// snip ...
var map = {
'app': '/app', // 'dist',
'#angular': '/node_modules/#angular',
'angular2-in-memory-web-api': '/node_modules/angular2-in-memory-web-api',
'rxjs': '/node_modules/rxjs'
};
// snip ...
ng2/views/index.html
Use absolute path
This won't stop the page from loading but a mess.
// snip ...
<link rel="stylesheet" href="/stylesheets/style.css">
// snip ...
Instead of app.use('/', routes);, register a middleware that will always serve the index.html. Be cautious though, this can cause your app to return index.html even inside the /docs route.
Just use the middleware that renders the index page:
app.use(routes);
Make sure the routes middleware itself always renders the page, not only on / path.
var express = require('express');
/* render home page. */
var router = function(req, res, next) {
res.render('index', { title: 'Express' });
};
module.exports = router;
Remove this the 404 handler (it should be automatic)
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
And change the node_modules route to the following (because SystemJS relies on 404 responses during resolution):
var modules = express.Router();
modules.use(express.static(__dirname + '/node_modules'));
modules.use(function(req, res, next) {
// Missing files inside node_modules must return 404
// for the module loader to work
res.sendStatus(404);
});
app.use('/node_modules', modules);

How to properly apply routes inside another file

I'm fairly new to express js and I want to know how to use router. I created a file named categories.js inside routes directory with this code.
categories.js code:
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/categories', function(req, res) {
res.send('this is the category');
});
module.exports = router;
inside the app.js i have this code:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var categories = require('./routes/categories');
var app = express();
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hjs');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
app.use('/categories', categories);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
I have tried understand what is wrong but i can't see to figure out. thanks in advance.
This is the error im getting
Not Found
404
I will like to add inside the routes directory i have a index.js file and this one works.
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
I think my application is not reading the categories.js file, because when I put the category.js code inside index.js it works. but it doesn't work if i put it in a separate file in my case category.js.
I think you've got your categories route hooked up wrong, your categories are mapped to /categories/categories in your code. To fix it, try this in your app.js:
app.use('/', categories);
If you don't want to prefix, you can also simply do this:
app.use(categories);

Failed to lookup view "error" in views directory using handlebars

I am new with express and handlebars. I wanted to use handlebars as a template engine on my express.js app but then I keep on receiving this kind of error:
which was get generated by this code
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var exphbr = require('express3-handlebars'); // "express3-handlebars"
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views/'));
//app.set('view engine', 'jade');
app.engine('handlebars', exphbr({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
/// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
what else am I missing or am I doing it right? Please help, I have been stuck for 1 day.
The issue is the following line
app.set('views', path.join(__dirname, 'views/'));
Express is looking for a file called error.jade in the folder views. If the file exists, possibly try removing the extra / from views/.
I just ran into a similar problem because I moved the views folder into another folder called app_server so the solution was to replace the line with
app.set('views', path.join(__dirname, '/app_server/views'));
You should have a View within your application currently named error.jade. Because you set up your application to use Handlebars the view engine is attempting to look for error.handlebars.
You should put modify the file and that will do it.
I had this issue when I upgraded the server.
All I had to do is run this
npm update
If the view engine is not set to jade/pug you have to use the extension right here:
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error.pug'); <<<<<HERE!
});

Categories