I'm trying to add a new route in my express app but I keep getting error when trying to start the server. The error is
C:\development\node\express_app\node_modules\express\lib\router\index.js:252
throw new Error(msg);
^
Error: .get() requires callback functions but got a [object Undefined]
here are my files, I'm new to node so let me know if i left out an important file
routes/furniture.js
exports.furniture = function(req, res){
res.render('furniture', { title: '4\267pli' });
};
routes/index.js
/*
* GET home page.
*/
exports.index = function(req, res){
res.render('index', { title: '4\267pli' });
};
views/furniture.ejs
<!DOCTYPE html>
<html>
<head>
<title>4·pli -- architecture</title>
<link rel='stylesheet' href='/stylesheets/style.css'/>
<link href='http://fonts.googleapis.com/css?family=Didact+Gothic' rel='stylesheet' type='text/css'>
</head>
<body>
<div class="wrapper">
<h1 class="logo"><%= title %></h1>
</div>
</body>
</html>
app.js
/**
* Module dependencies.
*/
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, furniture = require('./routes/furniture')
, http = require('http')
, path = require('path');
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(require('stylus').middleware(__dirname + '/public'));
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.get('/', routes.index);
app.get('/users', user.list);
app.get('/furniture', routes.furniture);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
The trouble is:
routes = require('./routes'),
user = require('./routes/user'),
furniture = require('./routes/furniture'),
These 3 are setting your routes folders, not a specific file, express will look for a index.js ( not found, then --> error)
Inside these folders, you should put a index.js with your:
exports.xxxx = function(req, res){
res.render('xx', { foo: foo});
};
Then, your project folder structure should look like:
routes/
├── index.js
│
├── user/
│ └── index.js (with a exports.user inside)
│
└── fourniture/
└── index.js (with a exports.furniture inside)
You can add multiple export functions to a route like these:
app.js
// a folder called routes with the index.js file inside
routes = require('./routes')
.
.
.
app.get('/', routes.main_function);
app.get('/sec_route', routes.sec_function);
app.post('/other_route', routes.other_function);
/routes/index.js
exports.main_function = function(req, res){
res.render('template1', { foo: foo });
};
exports.sec_function = function(req, res){
res.render('template2', { bar: bar });
};
exports.other_function = function(req, res){
res.render('template1', { baz: baz });
};
If your website is so big some times I prefer to do something like:
routes/furniture.js:
module.exports = function(app)
{
app.get("/furniture/", function(req, res) {
res.render('furniture', { title: '4\267plieee' });
});
}
And then in app.js:
require("./routes/furniture")(app);
It's mainly the same but app.js will be cleaner.
Although this is somewhat old, though of sharing the way i do this. Here is a another approach which makes code more cleaner and easy to add routes.
app.js
const app = express();
const routes = require('./routes');
app.use('/api', routes); //Main entry point
/routes/index.js
const router = require('express').Router();
const user = require('./user');
const admin = require('./admin');
//This is a simple route
router.get('/health-check', (req, res) =>
res.send('OK')
);
router.route('/users')
.post(validate, user.createUser);
router.route('/users/:userId')
.get(validateUser, user.getUser)
.patch(validateUser, user.updateUser)
.delete(validateUser, user.deleteUser);
router.route('/admins/:adminId/dashboard')
.get(validateAdmin,admin.getDashboard);
module.exports = router;
'validateUser' and 'validateAdmin' are custom middle wares, which will be used to validates request parameters or to do some pre-processing before request reach the actual request handler. This is optional and you can have multiple middleware (comma separated) as well.
/routes/user.js
module.exports = {
createUser:function(req,res,next){
},
updateUser:function(req,res,next){
},
deleteUser:function(req,res,next){
}
}
/routes/admin.js
module.exports = {
getDashboard:function(req,res,next){
}
}
Follow a simple and consistent folder structure, then use a module to have everything done automatically.
Then never look back. Spend time saved on the rest of the important stuff.
TL;DR
$ npm install express-routemagic --save
const magic = require('express-routemagic')
magic.use(app, __dirname, '[your route directory]')
That's it!
More info:
How you would do this? Let's start with file structuring:
project_folder
|--- routes
| |--- nested-folder
| | |--- index.js
| |--- a-file-that-doesnt-share-same-name-with-another-folder.js
| |--- index.js
|--- app.js
In app.js
const express = require('express')
const app = express()
const magic = require('express-routemagic')
magic.use(app, __dirname, 'routes')
In any of your routing files:
For e.g., index.js
const router = require('express').Router()
router.get('/', (req, res) => { ... })
router.get('/something-else', (req, res) => { ... })
Or a-file-that-doesnt-share-same-name-with-another-folder.js
Usually you might want to start a folder and use the index.js
pattern. But if it's a small file it's okay.
const router = require('express').Router()
const dir = 'a-file-that-do-not-have-another-folder-with-same-name' // you can use this to shorten, but it's optional.
router.get(`$(dir)/`, (req, res) => { ... })
router.get(`$(dir)/nested-route`, (req, res) => { ... })
Disclaimer: I wrote the package. But really it's long-overdue, it reached my limit to wait for someone to write it.
Related
It's probably a newbie question. I'm trying to setup my very first expressjs application and I need to use a view helpers that doesn't work for some reason.
Here is my server.js
var express = require('express');
var app = express();
var test = function(req, res, next) {
res.myLog = function(){
console.log("res");
return "Hello";
}
next();
}
app.use(test);
app.get("*", function(req, res) {
res.sendfile('./dist/index.html');
})
app.listen(5000);
And index.html
<html>
<head>
<title>Test application</title>
<link rel="stylesheet" href="main.css" />
<script src='<%=myLog()%>'></script>
</head>
<body>
<h1>Yo World!</h1>
</body>
</html>
myLog function is not call during rendering. Originally I was trying to use some third part helpers and they didn't work as well.
I haven't found any documentation of how to use the helpers on expressjs site. I'm clearly doing something wrong here.
Express version 4.3.14
To send file using express, correct ways is:
//sending html files
var express = require('express');
var app = express();
var path = require('path');
// viewed at http://localhost:5000
app.get('/', showClientRequest, function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
function showClientRequest(req, res, next) {
var request = {
REQUEST : {
HEADERS: req.headers,
BODY : req.body
}
}
console.log(request)
return next();
}
app.listen(5000);
Use ejs template engine:
var express = require('express');
var ejs = require('ejs');
var app = express();
app.set('view engine', 'ejs');
var path = require('path');
// viewed at http://localhost:5000
app.get('/', showClientRequest, function(req, res) {
res.render('index',{message:"Hello World!"});
});
function showClientRequest(req, res, next) {
console.log('Something Here...');
return next();
}
app.listen(5000);
Node-Cheat Available:
For complete code, get working node-cheat at express_server run node app followed by npm install express ejs.
Use res.locals.myLog instead of res.myLog to set locals. If you don't need req within your helper function you can also use app.locals.myLog.
res.sendfile will not render your view but just send a file as it is. You will have to use res.render and move your dist/index.html to views/index.ejs.
I was wondering how do I move all of my api routes in express into a separate routes.js file from my server.js file
I have a long list of api routes using app.use() for each route. So each route is in its own file, e.g. movies.js, movie.js but when I list these it makes for a long list in server.js
So I want to remove the list of api endpoints section from the below server.js out to a routes.js file.
Here is what I have currently:
server.js
import path from 'path'
import express from 'express'
import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackConfig from './webpack.config.dev'
const app = express();
/* api endpoints, can be many more, I want them in routes.js */
app.use('/api/movies', require('./src/api/routes/movies'))
app.use('/api/movie', require('./src/api/routes/movie'))
app.use(webpackDevMiddleware(webpack(webpackConfig), {
publicPath: webpackConfig.output.publicPath
}));
app.use('/public', express.static(__dirname + '/public'))
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
});
app.listen(3000, 'localhost', function (err) {
if (err) {
console.log(err);
return;
}
})
An example route
movies.js
var express = require('express');
var request = require("request");
var router = express.Router();
router.get('/', function(req, res) {
res.json({})
});
module.exports = router;
You can try to use the following modular approach.
Define controller files having logic per feature. e.g. movie.
movieController.js
module.exports = {
getMovie : function(req, res){
//do something
},
getMovies : function(req, res){
//do something
},
postMovie : function(req, res){
//do something
}
}
Then, reference that controller in routes files and simply plug those functions.
routes.js
var express = require('express');
var movieCtrl = require('./movieController');
var router = express.Router();
router.route('/movie').get(movieCtrl.getMovie);
router.route('/movie').post(movieCtrl.postMovie);
router.route('/movies').get(movieCtrl.getMovies);
module.exports = router;
And, in app.js, mount the routes to suitable location, e.g. /api
app.js
var routes = require('./routes');
app.use('/api', routes);
I am working on a single page web app with node/angular and jade. I am fairly new to angular, and I wanted to know what I have to do with my app.js file so that my first page template loads from my angular file rather than from my jade template.
I structured my files as such:
public/
index.html
javascript/
img/
stylesheets/
routes/
index.js
views/
partials/
a.jade
b.jade
app.js
This is what my app.js looks like:
var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.cookieParser('cookies monster')); // Cookie secret
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
/*
* Views
*/
app.get('/', routes.index);
app.get('/a', routes.a);
app.get('/b', routes.b);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
My index.js looks like this:
exports.index = function(req, res){
res.render('index', { title: 'Test Application' });
};
// View A
exports.a = function(req, res) {
res.render('partials/a', { layout: false, test: 'LOL' });
};
// View B
exports.b = function(req, res) {
res.render('partials/b', { layout: false, test: 'YOLO' });
};
When I run this, It does not use the index.html as the first page. How would I go about doing so, so that the initial page template is actually the index.html? I can't seem to find the answer anywhere.
You could return the actual index.html file from your router.
app.get('/', function(req, res, next){
return res.sendfile(app.get('public') + '/index.html');
});
I should note that I also put app.set('public', path.join(__dirname, 'public')); inside app.js for easy access to the public directory.
i am trying to create a route for localhost:port/admin/
and i want to keep the routes.js files and view.js files in matching folders so i wont have too much spaggeti later on
but i keep getting: 500 Error: Failed to lookup view "/admin/manage_subjects"
for trying to create a new route and using same folders few the same
i have the following view folder with express
mainapp(root)
routes(folder)
admin(folder)
index.js(nested inside admin)
index.js(nested inside routes)
views(folder)
admin(folder)
admin_layout.jade(nested inside admin)
manage_subjects.jade(nested inside admin)
index.jade(nested inside views)
layout.jade(nested inside views)
code:
routes/admin/index.js
exports.index = function (req, res) {
res.render('manage_subjects',{title:'Express'});}
views/admin/manage_subjects.jade
extends admin_layout
block content
h1 = title
p Welcome to #{title}
my app.js code
/**
* Module dependencies.
*/
var express = require('express')
, routes = require('./routes')
, admin_routes = require('./routes/admin/')
, user = require('./routes/user')
, http = require('http')
, path = require('path')
, repository = new (require('./domain_model/repository'))();
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
//fill local subjects
repository.subjects.GetAll(function (err, data) {
if (err) throw err;
app.locals.subjects = data;
});
//append routes
app.get('/', routes.index);
app.get('/admin', admin_routes.index);
app.get('/users', user.list);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on http://localhost:' + app.get('port'));
});
I've been dealing with what I think is the same problem and figured out how to fix it. So in case someone else comes across this problem I'm posting my solution.
So here is what I had that was causing 404's and 500's
app.js
var routes = require('./routes/index');
var admin = require('./routes/admin');
app.use('/', routes);
app.use('/admin', admin);
and here was my routes/index.js
//append routes
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.render('index', {title: 'Express'});
});
module.exports = router;
and my routes/admin.js:
var express = require('express');
var router = express.Router();
router.get('/admin', function(req, res) {
res.render('admin/index', {title: 'Express'});
});
module.exports = router;
by defining the second /admin inside the router.get() function I think I was effectively telling node to look for the html in my views folder under the following path views/admin/admin/index.ejs. So to fix that all I had to do was remove either the /admin from the router.get() or the /admin from the app.use()
So my working code now looks like this:
app.js
var routes = require('./routes/index');
var admin = require('./routes/admin');
app.use('/', routes);
app.use('/admin', admin); //I left the /admin here and instead removed the one in routes/admin.js
and here was my routes/index.js
//append routes
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.render('index', {title: 'Express'});
});
module.exports = router;
and my routes/admin.js:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) { //NOTICE THE CHANGE HERE
res.render('admin/index', {title: 'Express'});
});
module.exports = router;
So making that change made it so I could have sub folders in my views folder.
Simple Answer for sub-folders inside the views folder (mine is called frontend)
click here the picture to see the folder structure
file app.js
app.set('views', [path.join(__dirname, 'frontend'), path.join(__dirname, 'frontend/locked'), path.join(__dirname, 'frontend/template'), path.join(__dirname, 'frontend/public')]);
app.set('view engine', 'pug')
I'd check out TJ's video on Modular apps on his vimeo the best part about this work flow is your code becomes really flexible and it's alot easier to stay DRY.
Additionally I would do something like this with my app.set("views")
var path = require("path");
app.set('views', path.join(__dirname, 'views'));
// you can then extend this to the example for routes
Another alternative would be something like in your app.js file:
var express require("express")
var app = express()
var routes = require("./path/to/routes")(app)
and then routes would look like:
routes = function (app) {
app.get("/route", middleWareifYou.gotIt, route.handler || function (req, res) {
res.send("some msg");
});
};
module.exports = routes
Cheers, I hope this helps!
I had a similar problem and what worked for me was setting the views folder in both the main app file and in the router file too.
So in the main app.js file I had:
app.set('views', viewsFolderPath);
And inside my router.js file I also did the same thing:
app.set('views', viewsFolderPath);
Here is my basic node.js app with only two files:
app.js
var express = require('express')
, routes = require('./routes')
, http = require('http')
, path = require('path');
var app = express();
module.exports = {
test: "test"
};
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
// defining middlewares
app.get('/', routes.index);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
and my index.js:
var server = require('../app');
exports.index = function(req, res){
console.log(server);
res.send('Hello world');
};
My problem is when I go to http:\\localhost:3000 , I see in my console {} instead of {test: "test"} , it looks like the module.eports doesn't work correctly. Why ?
Requiring index.js from within app.js, and then requiring app.js from within index.js, looks like code smell to me. Additionally, if you use var app = module.exports = express() then Express is able to treat your app as middleware (so for instance, you could have a second app that requires the first app, and passes some requests to it.
When I need to access app inside another required file I do the following:
// ./routes/index.js
module.exports = function(app){
var routes = {};
routes.index = function(req, res){
console.log(app.myConfig);
res.send('Hello world');
};
return routes;
};
// ./app.js
var app = module.exports = express();
app.myConfig = {foo:'bar'};
var routes = require('./routes/index.js')(app);
You don't need to include app in index.js
indes.js should just be
exports.index = function(req, res){
console.log(server);
res.send('Hello world');
};
And I am assuming index.js is in the routes folder like so
app.js
routes
index.js