Introduction
I have built some back end functionality in Node (First time using Node). Problem is that the whole thing was built in one page (index.js) so now im following a few basic tutorials and setting out express router middleware and now trying to follow a modular MVC approach,
This code is simple but brakes when I separate into two pages Server.js and config.js. I know its a simple problem but i cant spot it. can someone help spot the problem and maybe improve the structure ?
Problem
I go to http://localhost:8080/about or a different route and I get
Cannot GET /about
rather than the correct print out.
back-end/server.js
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
// get an instance of router
var router = express.Router();
// START THE SERVER
// ==============================================
app.listen(port);
console.log('Server has started!! ' + port);
back-end/config.js
router.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
router.get('/', function(req, res) {
res.send('im the home page!');
});
// sample route with a route the way we're used to seeing it
router.get('/sample', function(req, res) {
res.send('this is a sample!');
});
router.get('/about', function(req, res) {
res.send('im the about page!');
});
app.route('/login')
.get(function(req, res) {
res.send('this is the login form');
})
.post(function(req, res) {
console.log('processing'); // shows on console when post is made
res.send('processing the login form!'); // output on postman
});
app.use('/', router);
As #SLaks said in his comment, you need to import (require) your backend/config.js file. But it's not as simple as that...
In node, variables are scoped to the file in which they appear, so if you simply add require('./config') to your server.js file, that's not going to work either, because the router variable in config.js is local to that file - it's not going to know about the router variable in server.js.
The solution to this is to have the config.js file export a function which the server.js file can use to configure stuff. For example
config.js
module.exports = function(router) {
// set up your router here with router.use, etc.
};
server.js
var configure = require('./config');
// after you set up your express router...
configure(router);
// now start listening
Related
I am developing an application and I have defined my custom routes in a different way. I am using Web Storm IDE to develop and it has a specific folder of routes where all the routes are kept individually. I have the following code in my directory /routes/about.js file:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('about', { title: 'About Us' });
});
module.exports = router;
Now in the app.js I have written the following code to include these route and use it:
var index = require('./routes/index');
var users = require('./routes/users');
var about = require('./routes/about');
app.use('/', index);
app.use('/users', users);
app.use('/about', about);
But when I click on about link, it does not open the page. Though, if I write the route in the app.js file directly as:
app.get('/about', function (req, res) {
res.render('about');
});
then it renders the page. Also, if I do not make separate routes and use the default routes file (/routes/index.js) and include this in that file, then also the code works fine. Can anyone explain or tell is there any mapping of these route files done which is missed by me, or I am doing something syntactically wrong
You probably created a route for /about/about. To fix, change the about router from this:
router.get('/about', ...);
to this:
router.get('/', ...);
This, then goes with:
app.use('/about', router);
which already includes the /about path. Everything in that router will already have /about at the beginning of the path.
Use below code in about file
app.get('/', function (req, res) {
res.render('about');
});
You have already defined '/about' route in main file so if you want to render page on '/about' so you need to define route like this '/' in about page.
For example route '/about/us' then function will be in about page :
app.get('/us', function (req, res) {
res.render('about us');
});
The method to redirect the route is correct, but you have not pass the route to app.
so you just need to do is ,
router.use('/about', about);
app.use('/', router);
Like wise add router in app
I'm new to javascript. I'm trying to make a RESTfull API using Node.js and Express.js
My directory structure is as follows
/server.js
/api/api.js
/api/location/location.js
I want to make the API modular. I want that all the requests (get/post/delete/push) beginning with /api/* to be handled by api.js and whatever routing be required, api.js should route it to proper module.
For example, if someone requests GET /api/location/abc/xyz then api.js will transfer control to location.js which will then transfer to abc.js which will finally transfer to xyz.js stored in directory /api/location/abc/xyz/xyz.js
How can I achieve this?
Code so far:
/server.js
var express = require('express');
var app = express();
var api = require('./api/api.js');
var location = require('./api/location/location.js');
//app.use('/api/location', location); //This works, but I want api.js to handle sub-routes!
app.use('/api', api);
app.get('/', function(req, res){
res.end('successful get/');
});
app.listen(12345);
/api/api.js
module.exports = function(req, res, next) {
res.end('successful get /api');
next();
};
//Add code to handle GET /api/location
/api/location/location.js
module.exports = function(req, res, next){
res.end('from location!');
next();
}
You would use express.Router([options]).
And write it that way:
/api/api.js
var router = require('express').Router();
router.get('/location', require('./api/location') );
module.exports = router;
/api/api/location.js
module.exports = function(req, res, next){
res.end('from location!');
}
And don't call next(); if you ended the response. You only call next() in your callback if you don't handle the response.
I don't know how complex your REST api will be later. But try to to keep the routing in a small number of file. Having a callback for the routing in an own file like /api/api/location.js is most likely not the best idea.
Having a rough time adding Socket.io in my Express 4 Routes. In my routes/index.js I have:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('index', { title: 'Express' });
});
router.post('/message', function(req, res) {
console.log("Post request hit.");
// res.contentType('text/xml');
console.log(appjs);
io.sockets.emit("display text", req);
// res.send('<Response><Sms>'+req.body+'</Sms></Response>');
});
module.exports = router;
but io is undefined. I have seen several examples of how to do this, but none that worked for me. Any help would be appreciated.
You need to pass your socket.io variable to the router module so that it has access. You could do this by wrapping your module in a function call.
var express = require('express');
var router = express.Router();
/* GET home page. */
var returnRouter = function(io) {
router.get('/', function(req, res, next) {
res.render('index', {
title: 'Express'
});
});
router.post('/message', function(req, res) {
console.log("Post request hit.");
// res.contentType('text/xml');
console.log(appjs);
io.sockets.emit("display text", req);
// res.send('<Response><Sms>'+req.body+'</Sms></Response>');
});
return router;
}
module.exports = returnRouter;
Then, whever you import this route you would call this function like: require(./routefile)(io)
Here's a good article about creating modules that require being passed a variable: Node.Js, Require and Exports
How about exploiting events? This could add an extra layer of self-awareness to the app, including socket messaging.
Since express's app() inherits from node's eventEmitter, I app.emit('EVENT_NAME', payload) at any point in my route handlers,
and then just handle that with app.on('EVENT_NAME', function(payload){})
with any logic available. I'm using it in my current setup.
This is super old, but I was looking to do the same thing and didn't find a suitable answer. I came up with a good solution using app.set('socketio', io) and req.app.get('socketio') in my route. I was then able to create a reference to the sender's socket in my route without using io.on().
See the answer I added here for the code:
Use socket.io inside a express routes file
I was having trouble settings up a very basic static file sever using express with Node.js. I set up a simple server.js but cannot see any files when I load the URL localhost:9000 in my web browser.
All I see is a page saying: Cannot get /
var express = require('express');
var app = express();
app.use(function(req, res, next) {
next();
});
app.use(express.static(__dirname));
app.listen(9000);
Simply you're exposing nothing. Do you have, for example, an index.html file? Try this:
app.get("/", function(req, res) {
res.sendfile("index.html");
});
Did you go through the NodeSchool workshoppers? They have step-by-step examples that cover this and more.
Here is the workshop for Express.
Here is my solution for the 'static' question in the workshop.
var express = require('express')
var app = express()
app.use(express.static(process.argv[3]||path.join(__dirname, 'public')));
app.use(require('stylus').middleware(__dirname + '/public'));
app.post('/form', function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end()
})
app.listen(process.argv[2])
Express does not create a directory listing. Even thought it does not list the files in the directory, it does serve them up when hitting them in the web browser.
Point the browser to the actual file:
http://localhost:9000/public/test.html
Originally I found this confusing because I had expected the express server to list directories; when seeing "something"... a page that said "Cannot get /" I assumed that page would normally have a list of files.
I am an absolutely newby in node.js and I try to create a new project via this technology. I use express framework but on the start I have a little trouble. I have solved this trouble with workaround but I have a question for next behavior:
My app.js
var express = require('express')
, routes = require('./routes/index')
, routes = require('./routes/login');
var app = module.exports = express.createServer();
console.log(app.env);
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
app.use( function(req, res, next) {
if (req.url == '/') {
res.render('index', { title: 'Express!' })
} else {
next();
}
});
//app.get('/', routes.index);
app.get('/login', routes.login);
app.listen(3000, function(){
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});
In a block // Routes you can see app.use and app.get. If I try to use app.get instead of app.use I get error "cannot get /". I tried to put index.html file to my public folder. But fot "/" route I everytime got this file, not render of index.js.
app.get('/login', routes.login); - is work fine, but something wrong with "/" route. I dont want to leave my code in this state, please, help me understand this behavior.
Thank in advance.
Like the user PA. mentioned, the reason your code never finds the / url, is because you are redeclaring your routes variable:
var express = require('express')
, routes = require('./routes/index') // first declaration of 'routes'
, routes = require('./routes/login'); // re-declaration of 'routes'
This makes your first routes declaration (the declaration that was pointing to /index) unreachable by your code, which is why you get the error "cannot get /", because your routes variable only points to ./routes/login.
There are a few ways you can fix this to clean up your code:
1. Assign different variables for the different routes:
var express = require('express')
, index = require('./routes/index')
, login = require('./routes/login');
- 0R -
2. Put multiple functions in the routes file:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// in your routes/index file
exports.index = function(req, res){
res.render('index', { title: 'Index Page' });
};
exports.login = function(req, res){
res.render('login', { title: 'Login Page' });
};
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// in your app.js file
// import your 'routes' functions from your 'routes' file
var express = require('express')
, routes = require('./routes/')
// now use your routes functions like this:
app.get('/', routes.index);
app.get('/login', routes.login);
- OR -
In a large application, or for better code maintainability, you may want to break up your different routing functions into different files (instead of putting all your routing functions in one file, like the example above), so using the express default setup as an example, they are placing their user functions and their index functions in the routes folder this like:
routes /
user.js
index.js
Then, they setup their application like this:
var routes = require('./routes');
var user = require('./routes/user');
And call these functions like this:
app.get('/', routes.index); // calls the "index" function inside the routes/index.js
app.get('/users', user.list); // calls the "list" function inside the routes/user.js file
Hope this helps.
Quick tip: app.use() is used to create middleware, which is a function that will get called on each request in your application, giving you, the developer, access to the request object req, and the response object res, and the power to change, or enhance your application somehow. The ability to "act in the middle of a request" is a powerful feature, and the reason why it was working for you in your original example is because your app.use() middleware was getting called when the request for / was being called, even though your app couldn't find /, which was lost when you re-declared the routes variable, you were still making a request to /, which your app.use() was able to see (because middleware gets called on EVERY request, even the "bad" ones), so your middleware was still seeing the [invalid] request to / and acting like this:
// This middleware will get called on every request,
// even on the invalid request for '/'
app.use( function(req, res, next) {
// this line of code will see that the
// request is for "/" and fire
if (req.url == '/') {
// the page now appears to render, because you are forcing the
// res.render code inside of your middleware, which isn't always
// recommended, but it is working for you in this example
// because its the only place in your example that can do anything
// when the '/' request is made
res.render('index', { title: 'Express!' })
} else {
// this is common middleware design pattern, the next()
// function tells the express framework to "move on to the next function"
// in the middleware stack
next();
}
});