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();
}
});
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
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
I am building an application on top of elasticsearch using node.js and express.
This is my app.js:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon'); //serve-favicon is Express middleware for serving a favicon. The advantage over just a normal favicon.ico on your public/ directory is that this module also deals with cache control. You can remove this module if you like because Express doesn't depend on it.
var logger = require('morgan');
var cookieParser = require('cookie-parser');//ookie-parser is Express middleware that helps you with handling cookies. Your request object will have a cookies object which you can acces use in your app. If your app doesn't use cookies you can leave it out.
var bodyParser = require('body-parser');//body-parser is Express middleware you probably want to use if you're doing anything with forms. It will add a body object to your request so that you can access POST parameters.
var routes = require('./routes/index'); //routes / users are two dummy pages to show you how routing works. You could do all the routing in app.js but it will get messy as your application gets bigger.
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));//These 2 lines set the views folder and the view engine. It tells Express to use the /views folder in your app directory.
app.set('view engine', 'ejs');//to use ejs engine
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev')); //This method tells the app to use the parameters you're giving it. logger('dev') logs the requests to the console as seen above. The dev parameter means it will log a lot of information about the request such as the method, status code and response time.
app.use(bodyParser.json()); //bodyParser.json() gives your app the ability to parse JSON. This is necessary for when you're sending data (which you probably will with a JavaScript application) in JSON format.
app.use(bodyParser.urlencoded({ extended: false }));//bodyParser.urlencoded({ extended: false }) allows your app to read data from URLs (GET requests). Extended is true by default but you'll need the querystring module.
app.use(cookieParser());//cookieParser() adds an cookie object to all the requests you get.
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);//The first parameter is the path, the second one is the function to execute. We separate the routes from the app.js because we don't want our app to be one big mess. Separating files in Node makes use of module.exports.
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {//In Express a 404 is not the result of an error but rather the app running out of options. Once the request doesn't match any of the routes, it will reach the following function.
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;
This is my Javascript file(index.ejs) which is connecting to elasticsearch client:
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
<form action='/search-results' method='post'>
<input type="text" name="searchTerm" placeholder="your search term here">
<button type="submit"> SEARCH </button>
</form>
<ul>
<% if(locals.results) { %>
<pre>
<%= JSON.stringify(results,null,2) %>
</pre>
<% results.forEach( function( result )) %>
<% } %>
</ul>
</body>
</html>
This is my routes/index.js(JavaScript file):
var fs = require('fs');
//var path = "output.json";
var express = require('express'); //To make use of Express' routing capabilities you need to initiate a new Express Router.
var router = express.Router(); //To make use of Express' routing capabilities you need to initiate a new Express Router. get, put, post, delete, all
var searchModule = require('../search_module/search.js');
//There are two ways of using the router methods. You can define one route (for example /home) and attach the methods to it, or you can create a new method for each route.
/* GET home page. */
router.get('/', function(req, res) { //.get() - when you visit a website you make a GET request. You can get data from a URL in a GET request too.
res.render('index', { title: 'Express' });
});
router.post('/search-results', function(req, res) {//.post() is a method used everywhere for posting data to a server / app. You'll want to use this for submitting forms.
searchModule.search(req.body, function(data) {
res.render('index', { title: 'Express', results: data });
});
});
// fs.writeFile(path,data,function(err){
// if(err) console.error(err);
// })
module.exports = router;
This is how my browser looks like after I search for "white" query:
http://i.stack.imgur.com/A10BO.png
I want to store this result(JSON result) in a file(output.json). I want to append the output to the local file. I tried using fs.writeFile method, but I was not successful. Is there any other way to store the results in a file?
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.
I tried to separate my node routing into two parts: HTML/App and REST. Here is what I've done:
app.js:
var appPort = process.env.PORT || 80;
var express = require('express');
var http = require('http');
var appRouter = require('./routes/index');
var restRouter = require('./routes/rest');
var app = express();
var srv = http.createServer(app);
app.set('port', appPort);
app.set('view engine', 'jade');
app.use(express.static(path.join(__dirname, 'public')));
app.use('/api/rest/', restRouter); // this seems not working .. I never get the expected response
app.use('/', appRouter); // I get this even with localhost/api/rest/...
var server = srv.listen(app.get('port'), function() {
debug('Express server listening ' + server.address().address + ':' + server.address().port);
});
index.js:
var express = require('express');
var router = express.Router();
router.get('/*', function (req, res) {
res.send('HOME')
});
module.exports = router;
rest.js
var express = require('express');
var router = express.Router();
router.get('/api/rest/*', function(req, res) {
res.send('REST API');
});
module.exports = router;
My questions:
1. It's possible in general to build multiple routers in this way?
2. Does the sequence of get.use matter, and/or do I have to deal with 'next'?
3. In case I would like to access a database inside the router can I hand over a parameter like this:
// ...
var client = new pg.Client(dbConnection);
// ...
app.use('/', appRouter(client));
1) It is possible to build multiple routers this way.
Because you are using this:
app.use('/api/rest/', restRouter);
your route calls in rest.js will be relative to /api/rest/ which means your code should be modified in rest.js to look like this:
router.get('*', function(req, res) {
res.send('REST API');
});
I would also encourage you to see the Express multi-router example on GitHub. It illustrates this point very clearly by showing a REST app with versioned routes.
2) The order of things matter
See the Express documentation for app.use and you will note:
Middleware functions are executed sequentially, therefore the order of
middleware inclusion is important.
If you reverse the order of your app.use calls, the router.get('/*', function (req, res) { line in index.js will catch everything before you get to other routes...defeating your purpose.
Also, if you don't call next, Express has no way to know that you are done or even that you want to continue to the next middleware or route.
3) The database question is a modules/scope question
This is more of a scope question than an Express question. I'd suggest looking up some of the excellent writing about javascript scope and also on how Node handles modules.