I am following along with this article, which describes a good way to organize routes in express. I am encountering a problem though when i try to access the functions that i have exported from my main.js file. I get a 404 error when i curl "localhost/user/username"
//the routes section of my my app.js file
app.get('/', routes.index);
app.get('/user/:username', routes.getUser);
//my index.js file
require('./main');
require('./users');
exports.index = function(req, res) {
res.render('index', {title: 'Express'});
};
//my main.js file
exports.getUser = function(req, res){
console.log('this is getUser');
res.end();
};
----EDITED WITH MY SOLUTION----
Here is the solution that I went with, maybe someone will find it useful. I'm also open to hearing suggestions about whether or not this is going to cause me any problems in the future.
//-------The routes in my app.js file now look like this.
require('./routes/index')(app);
require('./routes/main')(app);
//-------In index.js i now have this
module.exports = function(app) {
app.get('/', function(req,res){
res.render('index', {title: 'Express'});
});
};
//-------My main.js now looks like this-------
module.exports = function(app){
app.get('/user/:username', function(req, res){
var crawlUser = require('../engine/crawlUser');
var username = req.params.username;
crawlUser(username);
res.end();
});
};
Globals are evil and should be avoided at all costs. Here is how I organize my routes without globals and without excessive boiler plate code.
// File Structure
/app.js
/routes
/--index.js
/--main.js
/--users.js
// app.js
var app = require('express');
/* Call Middleware here */
require('routes')(app);
app.listen(3000);
---------------------------------------------
// routes/index.js - This is where I store all my route definitions
// in a long list organized by comments. Allows you to only need to go to
// one place to edit route definitions.
module.exports = function(app) {
var main = require('./main');
app.get('/', main.get);
var users = require('./users');
app.get('/users/:param', users.get);
...
}
---------------------------------------------
// routes/main.js - Then in each submodule you define each function and attach
// to exports
exports.get = function(req, res, next){
// Do stuff here
})
I guess in the end its a matter of preference, but if you want your code to maintain agility and work with other modules you should avoid global variables. Even if Alex Young says its ok. =)
Here is the solution that I went with, maybe someone will find it useful.
//-------The routes in my app.js file now look like this.
require('./routes/index')(app);
require('./routes/main')(app);
//-------In index.js i now have this
module.exports = function(app) {
app.get('/', function(req,res){
res.render('index', {title: 'Express'});
});
};
//-------My main.js now looks like this-------
module.exports = function(app){
app.get('/user/:username', function(req, res){
var crawlUser = require('../engine/crawlUser');
var username = req.params.username;
crawlUser(username);
res.end();
});
};
Related
I know I can do this in Express:
app.use('/:id', function (req, res){ // or app.get
console.log('Test param: ' + req.params.id); // "Test param: foo"
});
to get my url parameter.
When I try to use a router logic I did:
index.js
var sites = require('./routes/sites');
app.use('/:id', sites);
routes/sites.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
console.log(req.params.id); // logs "undefined"
// etc ...
});
module.exports = router;
this logic does not work, I get {} in the shell command, undefined for req.params.id.
Any idea where my logic is wrong?
It doesn't work, because that's just not how express interacts with its Routers. The reason you're not seeing id inside your router, is because :id was not declared within its scope. You'd need to do something like
app.use('/', sites);
and in your router
var express = require('express');
var router = express.Router();
router.get('/:id', function(req, res, next) {
console.log(req.params.id);
// etc ...
});
module.exports = router;
Additionally you can try playing around with app.param() see docs for examples http://expressjs.com/api.html#app.param
When you are trying to do this in index.js and routes.js -
app.use('/:id', function (req, res){ // or app.get
console.log('Test param: ' + req.params.id); // "Test param: foo"
});
router.get('/', function(req, res, next) {
console.log(req.params.id); // logs "undefined"
// etc ...
});
"id" is not defined there because that's how express works with routers, it just matches the routes matching with the specified prefix in app.use() method. For that, you can try using -
const express = require('express');
const router = express.Router({mergeParams: true});
Now it will work perfectly.
It actually works now.
You can do something like
app.use('/:id/transactions', require('./routes/transactions'));
In the main file, and then add {mergeParams:true} to Router options in the controller file.
const router = require('express').Router({mergeParams:true});
So here you will be able to get the id that was set in base Route.
// localhost:5000/:id/transactions/
router.get('/',(req, res) => {
console.log(req.params.id);
}
Found here:
http://expressjs.com/api.html#app.param
In your file router/sites.js, add an option to express router:
const router = express.Router({mergeParams:true});
Now you have access to id in sites.js file.
I just started to learn node.js with express 4. I have read some books and tutorials, I also cloned some sample apps from git but I still have a very basic question, which practice should I follow to write the routing(or controller)?
Some people define all the routes in app.js, and export all the functions in the controller:
app.js
....
var homeController = require('./controllers/home');
var userController = require('./controllers/user');
....
app.get('/', homeController.index);
app.get('/login', userController.getLogin);
app.get('/logout', userController.logOUT);
app.get('/doStuff', userController.doStuff);
then in controllers/user.js
exports.getLogin = function(req, res) {
//logic...
});
exports.logout = function(req, res) {
//logic...
});
exports.doStuff = function(req, res) {
//logic...
});
Another way is like express-generator way:
app.js
...
app.use('/users', users);
...
controllers/users.js
....
router.get('/login', function(req, res, next) {
//logic...
});
router.get('/logout', function(req, res, next) {
//logic...
});
router.get('/doStuff', function(req, res, next) {
//logic...
});
module.exports = router;
And other are more dynamic like this proposal
is there any technical difference? Which pattern should I follow?
This is completely preferential. Any pattern that works is likely to be valid here. Express routers make things very nice and easy to setup. Personally I prefer to create a directory for every top level route, files for the second level, and exports for the third. Here's an example of how I lay things out for a set of API routes.
Directory:
routes/
index.js <- master route manifest
api/
index.js <- api routes manifest
books.js
authors.js
landing-pages/
index.js
awesome-deal.js
Route manifest:
// routes/index.js
var router = require('express').Router();
router.use('/api', require('./api'));
router.use('/landing', require('./landing-pages'));
module.exports = router;
API routes manifest:
// routes/api/index.js
var router = require('express').Router();
router.use('/books', require('./books.js'));
router.use('/authors', require('./authors.js'));
module.exports = router;
Entity endpoints:
// routes/api/books.js
var router = require('express').Router();
var db = require('mongoose-simpledb').db;
router.get('/get/:id', function (req, res) {
var id = req.param('id');
db.Book.findOneById(id, function (err, book) {
if (err) throw err;
res.json(book);
});
});
router.post('/new', /* etc... */);
return router;
Then in my app file I only setup the the top-level route:
// app.js
/* express setup.... */
app.use('/', require('./routes'));
Without resorting to regular expression is there anyway with expressjs to recursively call routing ie url examples:
/f:forum/s:section/t:thread/p:post
/f:forum/s:section/s:section/t:thread/p:post
/f:forum/s:section/s:section/s:section/t:thread/p:post
...
Therefore allowing technically an infinite amount of "sections/subsections" in the forum.
I attempted to do:
app.js:
var express = require('express');
app = express();
app.route('/').get(function(req, res, next){
return res.send('hello');
});
app.use('/f:forum', require('./section'));
server = app.listen(process.env.http || process.env.PORT);
module.exports = app;
section.js:
var router = require('express').Router();
router = router;
router.route('/s:section').get(function(req, res, next){
return res.send(req.params);
});
router.use('/s:section', require('./thread'));
module.exports = router;
thread.js:
var router = require('express').Router();
router.use('/s:section', require('./section'));
router.route('/t:thread/p-:post').get(function(req, res, next){
return res.send(req.params);
});
router.route('/t:thread').get(function(req, res, next){
return res.send(req.params);
});
module.exports = router;
but interestingly it tells me that in thread.js require('./section') = {}
yet in app.js it is correct... any suggestions?
You can do wildcard routing like router.route('/:path*') and then have the handler parse from that point down.
For example, something like:
router.route('/forum/:path*', function(req,res){
var requestPath = req.path; // will present the whole path to you for parsing
// do whatever db lookup logic you normally would do now that you have the pieces you wanted
res.render('forum', data);
};
I'm creating an app using Node and Express. However, I can see it'll soon become difficult to manage all the routes that are placed inside app.js. I have placed all my models in a subdirectory /models.
Here's my app current structure:
app.js
models
-- products
-- customers
-- ...
public
views
node_modules
In app.js:
var express = require('express'),
routes = require('./routes'),
user = require('./routes/user'),
http = require('http'),
path = require('path'),
EmployeeProvider = require('./models/employeeprovider').EmployeeProvider,
Products = require('./models/products').Products,
Orders = require('./models/orders').Orders,
Customers = require('./models/customers').Customers,
checkAuth = function(req, res, next) {
if (!req.session.user_id) {
res.send('You are not authorized to view this page');
} else {
next();
}
};
var app = express();
Then some configuration like port, views directory, rendering engine, etc.
Further down app.js I've got the routes:
app.get('/product/edit', auth, function(req, res) {
Products.findAll(function(error, prds) {
res.render('product_edit', {
title: 'New Product',
products: prds
});
});
});
At the top I'm assigning the contents of models/products.js to a variable, all works fine. However keeping all routes inside app.js is not ideal. But if I move the routes to routes/product.js and load the Products models:
var prod = require('../models/products.js');
I get an error saying that object has no method findAll.
What am I doing wrong? How can I remove the routes from app.js?
As of express 4.x Router is added to support your case.
A router object is an isolated instance of middleware and routes. You can think of it as a “mini-application,” capable only of performing middleware and routing functions. Every Express application has a built-in app router.
Example from expressjs site:
// routes/calendarRouter.js
var express = require('express');
var router = express.Router();
// invoked for any requested passed to this router
router.use(function(req, res, next) {
// .. some logic here .. like any other middleware
next();
});
// will handle any request that ends in /events
// depends on where the router is "use()'d"
router.get('/events', function(req, res, next) {
// ..
});
module.exports = router;
Then in app.js:
// skipping part that sets up app
var calendarRouter = require('./routes/calendarRouter');
// only requests to /calendar/* will be sent to our "router"
app.use('/calendar', calendarRouter);
// rest of logic
Since I don't like repetition, here's what I do:
// app.js
//...
var routes = requireDir('./routes'); // https://www.npmjs.org/package/require-dir
for (var i in routes) app.use('/', routes[i]);
//...
And each file in routes is like:
// routes/someroute.js
var express = require('express');
var router = express.Router();
router.get('/someroute', function(req, res) {
res.render('someview', {});
});
module.exports = router;
This way you can avoid long repetitive lists like this one:
app.use('/' , require('./routes/index'));
app.use('/repetition' , require('./routes/repetition'));
app.use('/is' , require('./routes/is'));
app.use('/so' , require('./routes/so'));
app.use('/damn' , require('./routes/damn'));
app.use('/boring' , require('./routes/boring'));
Edit: these long examples assume each route file contains something like the following:
var router = express.Router();
router.get('/', function(req, res, next) {
// ...
next();
});
module.exports = router;
All of them could be mounted to "root", but what for them is "root", is actually a specific path given to app.use, because you can mount routes into specific paths (this also supports things like specifying the path with a regex, Express is quite neat in regards to what you can do with routing).
I can suggest you this file structure (according to Modular web applications with Node.js and Express from tjholowaychuk):
app.js
modules
users
index.js
model.js
users-api
index.js
static-pages
index.js
user-api and static-pages export expressjs applications, you can easily mount them in app.js.
In users module you can describe some Data Access operations and all methods about manipulating with the User entity (like create, update etc.). Our API module will use all these methods.
And here is sample code of app.js file (without common express stuff, only mounting routes from different modules):
var express = require('express');
var app = express();
// mount all the applications
app.use('/api/v1', require("user-api"));
app.use(require("static-pages"));
app.listen(3000);
To use your modules this way you must start your app like this NODE_PATH=modules node app.js (i put this line to package.json file in scripts section).
Here is sample code of users module:
index.js
User = require("./model");
module.exports = {
get: function(id, callback) {
User.findOne(id, function(err, user) {
callback(err, user);
});
},
create: function(data, callback) {
// do whatever with incoming data here
data = modifyDataInSomeWay(data);
var newUser = new User(data);
newUser.save(function(err, savedUser) {
// some logic here
callback(err, savedUser);
});
}
};
model.js (with Mongoose stuff for example of course!)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var User = new Schema({
firstname : {type: String, required: false},
lastname : {type: String, required: false},
email : {type: String, required: true}
});
module.exports = mongoose.model('user', User);
And example of user-api module (here is the main part of the answer about separating routes and models).
var users = require("users");
var express = require("express");
var app = module.exports = express(); // we export new express app here!
app.post('/users', function(req, res, next) {
// try to use high-level calls here
// if you want something complex just create another special module for this
users.create(req.body, function(err, user) {
if(err) return next(err); // do something on error
res.json(user); // return user json if ok
});
});
And example of static-pages. If you are not going to build a kind of REST interface you may simply create several modules that will render pages only.
var express = require("express");
var app = module.exports = express(); // we export new express app here again!
app.get('/', function(req, res, next) {
res.render('index', {user: req.user});
});
app.get('/about', function(req, res, next) {
// get data somewhere and put it in the template
res.render('about', {data: data});
});
Of course you can do whatever you want with modules. The main idea about expressjs is to use a lot of small apps instead of single one.
About nodejs modules you can read stackoverflow and docs.
Hope this helps.
I am getting my hands on node.js and I am trying to understand the whole require/exports thing. I have the following main app.js file:
/app.js
var express = require('express'),
http = require('http'),
redis = require('redis'),
routes = require('./routes'),
var app = express(),
client = redis.createClient();
// some more stuff here...
// and my routes
app.get('/', routes.index);
then, I have the routes file:
exports.index = function(req, res){
res.render('index', { title: 'Express' });
};
I can of course use the client object on my app.js file, but how can I use the same object in my routes?
Since req and res are already being passed around by Express, you can attach client to one or both in a custom middleware:
app.use(function (req, res, next) {
req.client = res.client = client;
next();
});
Note that order does matter with middleware, so this will need to be before app.use(app.router);.
But, then you can access the client within any route handlers:
exports.index = function(req, res){
req.client.get(..., function (err, ...) {
res.render('index', { title: 'Express' });
});
};
The easiest way is to export a function from your routes file that takes a client, and returns an object with your routes:
exports = module.exports = function (client) {
return {
index: function (req, res) {
// use client here, as needed
res.render('index', { title: 'Express' });
}
};
};
Then from app.js:
var client = redis.createClient(),
routes = require('./routes')(client);