Routers and controllers

So far, you have your server.js file and a configure module that is used to wire up all of the necessary middleware for the application. The next step is to implement a proper router and controller.

The router is going to be a map of each of the available URL paths for the app. Every route on the server will correspond to a function in a controller. Here is what our routes table will look like for the particular application we are writing:

GET  /(index) - home.index (render the homepage of the site)
GET  /images/image_id -
 image.index (render the page for a specific image)
POST /images - image.create (when a user submits and uploads a new image)
POST /images/image_id/like - image.like (when a user clicks the Like button)
POST /images/image_id/comment - image.comment (when a user posts a comment)

You can see that we are handling two different GET requests and three different POST requests. In addition, we have two main controllers: home and image. Controllers are really just modules with different functions defined that match up to the corresponding routes. We're calling them controllers because we're using the MVC design pattern, or Model View Controller. Typically, every route will correspond to a controller. This controller will more than likely render a view, and that view will more than likely have its own model (any data that is displayed in the view). You can learn more about MVC by visiting the following Wikipedia page:

http://en.wikipedia.org/wiki/Model-view-controller

Let's write our router as its own module, matching the table I outlined. First, create a routes.js file within the server folder. The routes file is going to be pretty simple, and the only dependencies it requires will be the controllers we define:

var home = require('../controllers/home'),
    image = require('../controllers/image'),

module.exports.initialize = function(app) {
    app.get('/', home.index);
    app.get('/images/:image_id', image.index);

    app.post('/images', image.create);
    app.post('/images/:image_id/like', image.like);
    app.post('/images/:image_id/comment', image.comment);
};

Right off the bat, we declare variables for both of our controllers and require each from the controllers folder (we haven't yet created these files but that's coming up next). Then, we export a module that contains an initialize function, which accepts our application as its only parameter. Inside the module, we define each of our routes.

The first parameter for a route is the string value of the route itself, which can contain variable values as sub paths. You can see with second app.get, we assign a route value of '/images/:image_id' that basically equates to '/image/ANYVALUE' in the browser address bar. When we write the image.index controller, you will see how to retrieve the value for :image_id and use it within the controller function itself.

The second parameter for a route is a callback function. You can completely omit the idea of using controllers and just define your callbacks as inline anonymous functions; however, as your routes grow, this file will get larger and larger, and the code will start to become a mess. It's always good practice to break your code up into as many small and manageable modules as possible to keep yourself sane!

The first two app.get routes are typical routes that would be called whenever a visitor points their browser to yourdomain.com/routepath—the browser by default sends a GET request to the server. The other three app.post routes are defined to handle when the browser POSTs a request to the server, typically done via an HTML form submission.

With all of our routes defined, let's now create the matching controllers. Within the controllers folder, create both the home.js and image.js files. The home.js file is very basic:

module.exports = {
    index: function(req, res) {
        res.send('The home:index controller'),
    }
};

With this module, we are actually exporting an object that has a single function called index. The function signature for index is the signature that is required for every route using Express. The first parameter is a request object and the second parameter is a response object. Every detail specific to the request that the browser sent to the server will be available via the request object. In addition, the request object will be modified using all of the middleware that was declared earlier. You will use the response object to send a response back to the client—this may be a rendered HTML page, static asset, JSON data, an error, or whatever you determine. For now, our controllers just respond with simple text so you can see that they are all working.

Let's create the image controller that has a few more functions. Edit the /controllers/image.js file and insert the following code:

module.exports = {
    index: function(req, res) {
        res.send('The image:index controller ' + req.params.image_id);
    },
    create: function(req, res) {
        res.send('The image:create POST controller'),
    },
    like: function(req, res) {
        res.send('The image:like POST controller'),
    },
    comment: function(req, res) {
        res.send('The image:comment POST controller'),
    }
};

Here, we defined the index function, just like we did in the home controller, except that we will also display image_id that is set in the route when this controller function is executed. The params property was added to the request object via the urlencoded Connect middleware!

Take note that neither controller currently requires any dependencies (there were no require declarations defined at the top of the file). This will change as we actually flesh out the controller functions and start to do things such as inserting records into our MongoDB database and using other third-party npm modules.

Now that your controllers are created and ready to be used, you just need to activate your routes. To do this, we will insert one last line of code in our configure.js file, right above the return app; line:

routes.initialize(app);

Don't forget to uncomment the routes = require('./routes'), line at the top of the file as well. What we're doing here is using the routes module we defined and executing the initialize function, which will actually wire up our routes via our app object.

As a recap of each of the files you have created so far, here are the uninterrupted files listed so you can view the full code:

  1. First, we have the boot up with server.js:
    var express = require('express'),
        config = require('./server/configure'),
        app = express();
    
    app.set('port', process.env.PORT || 3300);
    app.set('views', __dirname + '/views'),
    app = config(app);
    
    var server = app.listen(app.get('port'), function() {
        console.log('Server up: http://localhost:' + app.get('port'));
    });
  2. Next, we will configure the server with server/configure.js:
    var connect = require('connect'),
        path = require('path'),
        routes = require('./routes'),
        exphbs = require('express3-handlebars'),
    
    module.exports = function(app) {
        app.engine('handlebars', exphbs.create({
            defaultLayout: 'main',
            layoutsDir: app.get('views') + '/layouts',
            partialsDir: [app.get('views') + '/partials']
        }).engine);
        app.set('view engine', 'handlebars'),
    
        app.use(connect.logger('dev'));
        app.use(connect.bodyParser({
            uploadDir:path.join(__dirname, '../public/upload/temp')
        }));
        app.use(connect.json());
        app.use(connect.urlencoded());
        app.use(connect.methodOverride());
        app.use(connect.cookieParser('some-secret-value-here'));
        app.use(app.router);
        app.use('/public/', connect.static(path.join(__dirname, '../public')));
    
        if ('development' === app.get('env')) {
            app.use(connect.errorHandler());
        }
    
        routes.initialize(app);
    
        return app;
    };
  3. Then, we have our routes defined in server/routes.js:
    var home = require('../controllers/home'),
        image = require('../controllers/image'),
    
    module.exports.initialize = function(app) {
        app.get('/', home.index);
        app.get('/images/:image_id', image.index);
    
        app.post('/images', image.create);
        app.post('/images/:image_id/like', image.like);
        app.post('/images/:image_id/comment', image.comment);
    };
  4. Finally, we will define our controllers with controllers/home.js:
    module.exports = {
        index: function(req, res) {
            res.send('The home:index controller'),
        }
    };

    And controllers/image.js:

    module.exports = {
        index: function(req, res) {
            res.send('The image:index controller ' + req.params.image_id);
        },
        create: function(req, res) {
            res.send('The image:create POST controller'),
        },
        like: function(req, res) {
            res.send('The image:like POST controller'),
        },
        comment: function(req, res) {
            res.send('The image:comment POST controller'),
        }
    };

Let's fire up the server one last time and check whether it's all working. Execute node server.js, and this time point your browser to http://localhost:3300. Now, you should be seeing some responses in the browser. Try going to http://localhost:3300/images/testing123. You should see The image:index controller testing123 on the screen!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.183.152