Express node.js - understanding routing - javascript

I have this about.js route and it works fine but I don't understand how / in router.get() would work while /about wouldn't?
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('about', { title: 'About' });
});
module.exports = router;
----------------- UPDATE ----------------------
It's basically what I got out of the box after installing express.js
except the about lines.
I expected router.get('/about' ...) in about.js would work but it threw an error and it worked with / instead and that's what bugs me.
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 users = require('./routes/users');
var about = require('./routes/about');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// 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);
app.use('/users', users);
app.use('/about', about);
// 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;

The problem
When you define a route on your app.js as you did with app.use('/about', about);. You are already telling express that you expect requests to hit http://yourserver/about route.
If you try to define /about again inside your about.js with:
router.get('/', function(req, res, next) {
res.render('about', { title: 'About' });
});
What you're doing is tellig the Express that you will hit a /about inside your firstly declared /about. So it will expect requests on this route: http://yourserver/about/about
The solution
It's actually what you're using. Define a root route inside your about.js as:
router.get('/', function(req, res, next) {
res.render('about', { title: 'About' });
});
This way your app will be:
Modular since you're using different files for different routes (about.js, users.js)
Easier to read
With simplier routes inside each file, since you don't need to type /about everytime you wish to create a new route.
If you wish a http://yourserver/about/help simply add a handler inside your route file about.js as here:
router.get('/help', function(req, res, next) {
res.render('help', { title: 'Help' });
});

If you want the route /about work then you have to create another route:
router.get('/about', function(req, res, next) {
res.render('about-page', { title: 'About' });
});
because / will only work for the home page.

Related

In Webstorm node express app: router.post() shows error: unresolved function or method post()

When I run the localhost:3000/users/yu , I get a 404 not found. Why is the post() coming up as undefined? when I run a POST from my iOS app I get a "undefined token" error. I'm running node v5.7.0 and express v4.13.4 Project was generated using express-generator to create Webstorm project.
var express = require('express');
var router = express.Router();
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res) {
res.send("yoma");
});
router.post('/yu', function(req, res) {
var test = req.body;
//parse test
});
My app.js looks like this:
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 app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// 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: true }));
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;
when you navigate your browser to localhost:3000/users/yu it makes GET http query, but in your router you have only POST handler for '/yu'
router.post('/yu', function(req, res) {
console.log(req.body);
});
Add GET handler for '/yu' like this for example
router.get('/yu', function(req, res) {
console.log(req.body);
});
After that you should not get a 404 error when navigate to localhost:3000/users/yu

404 Error in Node Application

Not Found
404
Error: Not Found
at c:\Users\wf\WebstormProjects\nodeExpress\app.js:33:13
at Layer.handle [as handle_request] (c:\Users\wf\WebstormProjects\nodeExpress\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (c:\Users\wf\WebstormProjects\nodeExpress\node_modules\express\lib\router\index.js:312:13)
at c:\Users\wf\WebstormProjects\nodeExpress\node_modules\express\lib\router\index.js:280:7
at Function.process_params (c:\Users\wf\WebstormProjects\nodeExpress\node_modules\express\lib\router\index.js:330:12)
at next (c:\Users\wf\WebstormProjects\nodeExpress\node_modules\express\lib\router\index.js:271:10)
at c:\Users\wf\WebstormProjects\nodeExpress\node_modules\express\lib\router\index.js:618:15
at next (c:\Users\wf\WebstormProjects\nodeExpress\node_modules\express\lib\router\index.js:256:14)
at Function.handle (c:\Users\wf\WebstormProjects\nodeExpress\node_modules\express\lib\router\index.js:176:3)
at router (c:\Users\wf\WebstormProjects\nodeExpress\node_modules\express\lib\router\index.js:46:12)
router code:
//about.js
var express = require('express');
var router = express.Router();
router.get('/about', function(req, res, next) {
console.log("/about route");
res.render('about', { title:'About',name:'Praveen' });
});
module.exports = router;
//app.js 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 about = require('./routes/about');
//var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// 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);
app.use('/about', about);
//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;
enter code here
I'm getting above error if I try to access different route in my node application. Please help
The issue here is that the route in the about file is actually being resolved as /about/about. If you try open that URL it should work fine.
This is because in app.js, you say 'forward all requests that start with /about to about.js', so in about.js all routes already start with /about: app.use('/about', about);
To fix this, simply update the route in about.js to:
router.get('/', function(req, res, next) {

Basic nodejs route resulting in 404

I am trying to create two separate routes in NodeJS, I am using the express framework and angular on the client side. I am currently able to render my index page successfully by visiting localhost:3000/ although when I try to render the login page by visiting localhost:3000/login I am getting a GET /login 404 error and not sure why b/c I set it up extremely similar to the index route. Not sure if I missed something.
This my app.js
//require dependencies
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');
//require routes but do not user yet
var routes = require('./routes/index');
var login = require('./routes/login');
//start app
var app = express();
// view engine setup - default views directory
app.set('views', path.join(__dirname, 'views'));
app.locals.delimiters = '<% %>';
app.set('view engine', 'hjs'); //use hogan templating for views
// 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(require('less-middleware')(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/login', login);
// 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;
routes/login.js
var express = require('express');
var router = express.Router();
router.get('/login', function(req, res){
res.render('login');
});
module.exports = router;
views/login.hjs
<!DOCTYPE html>
<html>
<head>
</head>
<body>
HELLO WORLD
</body>
</html>
Visiting localhost:3000/login renders the following:
{{ message }}
{{ error.status }}
{{ error.stack }}
When writing app.use('/login', login), you are telling Express to use your router under the namespace : '/login'; Therefore, all routes defined into login.js don't need this prefix.
Try to access localhost:3000/login/login ;)
Then, just change your router to:
router.get('/', function(req, res){
res.render('login');
});

Why the /users route in Express and Node?

Edit: The default express app is this:
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');
----------------------------------------
These refer to files that look like:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});
module.exports = router;
------------------------------
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// 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);
// 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;
However, the documentation says:
// this middleware will not allow the request to go beyond it
app.use(function(req, res, next) {
res.send('Hello World');
})
// requests will never reach this route
app.get('/', function (req, res) {
res.send('Welcome');
})
So my question, is why would a request ever make its way to the /users route when a default (i.e. '/') route has already been specified? Is it because routes and users are not functions?
On a related note, why even specify the / if that is what is used by default each time?
Lastly, the default app specifies the '/users' route: Why not just put another path in the index.js route? I am confused how the app can specify app.use('/users', users) and then, in the users route, specify
router.get('/', function(req, res) {
res.send('respond with a resource');
});
What does the / correspond to? It seemed like all requests to / would be handled by the first route (the one that use the routes default file)
app.use() is middleware. You pass it an optional path and a function and it is the function's job to decide if it wants to pass the request on to further middleware or further routes. It does that by calling next() or if it doesn't want to pass it on, it doesn't call next().
So, if you have:
app.use("/", fn);
That middleware will get called for all paths, but the code inside the function you pass it decides whether to pass the request on or not.
There are two routers in the Express 4 application skeleton: routes (mounted on '/') and users (mounted on '/users'). You may use both of them or only routes or you may even add more routers.
app.js:
var routes = require('./routes/index');
var users = require('./routes/users');
app.use('/users', users); // please note the mounting point!
app.use('/', routes);
users.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
Please note that router.get('/', ... ) for the users router means that the requested url is http://yourserver/users and not http://yourserver/

Node.js controllers

Im currently very new to Node.js - Express framework and Im trying to emulate a MVC pattern, so far I got this
app.js
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 http = require('http');
var app = module.exports = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.set('port', process.env.PORT || 3000);
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')));
require('./routes');
/// catch 404 and forwarding 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: {}
});
});
http.createServer(app).listen(app.get('port'), function() {
console.log("Running server");
});
Just a normal app.js generated with the express generator with some modifications, now my routes/index.js
app = require('../app');
app.get('/test', function(req, res) {
require('./controllers/test.js');
test();
});
app.get('/', function(req, res) {
res.send('yankevf');
});
As you can see on route /test if looks for module /controllers/test.js but since theres no actual module it wont work..
How can I include a file that is inside the folder controllers? since my server keeps searching inside node_modules
It looks like you're basically there...
From your question it sounds like your folder structure is:
./app.js
./routes
-> index.js
./controllers
-> test.js
If that's the case, this should work:
app = require('../app');
app.get('/test', function(req, res, next) {
test = require('../controllers/test.js'); // Note the path, one directory up
// Passing the req, res, next arguments on to your controller allows it to respond
// i.e. res.json({msg: 'hello world'}).
test(req, res, next);
});
Although you probably don't want to load your controller on every new request, but rather load (require) it once, and call it on every request:
app = require('../app');
testController = require('../controllers/test.js');
app.get('/test', function(req, res, next) {
// Passing the req, res, next arguments on to your controller allows it to respond
// i.e. res.json({msg: 'hello world'}).
testController(req, res, next);
});
If you're directly passing these arguments to your controller (like you should), you can write it more succinctly:
app = require('../app');
testController = require('../controllers/test.js');
// Call your controller, automatically passing 'req', 'res', 'next' arguments.
app.get('/test', testController);
For a full example which automates the mounting of routes, checkout: Express MVC example

Categories

Resources