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 proper routers and the necessary controllers.

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 with the corresponding routes. As pointed out earlier, they are called controllers in MVC design patterns. 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).

Let's write our router as its own module matching the table 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:

const express = require('express'), 
    router = express.Router(), 
    home = require('../controllers/home'), 
    image = require('../controllers/image'); 
module.exports = (app)=>{ 
    router.get('/', home.index); 
    router.get('/images/:image_id', image.index); 
    router.post('/images', image.create); 
    router.post('/images/:image_id/like', image.like); 
    router.post('/images/:image_id/comment', image.comment); 
    app.use(router); 
}; 

Right off the bat, we declare a router variable and require the controllers folder to assign each application route (we haven't yet created these files, but that's coming up next). Here, we are assigning each route to its corresponding function in the controllers. Then, we export a module that, when invoked by itself, will attach all these routes to the app instance.

The first parameter for a route is the string value of the route itself, which can contain variable values as subpaths. You can see with the second router.get, that 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 a good practice to break your code up into as many small and manageable modules as possible to keep yourself sane!

The first two router.get routes are typical routes that would be called whenever a visitor points their browser to yourdomain.com/routepath—the browser sends a GET request to the server by default. The other three router.post routes are defined to handle when the browser posts a request to the server, typically done via a 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(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. A first parameter is a request object and a 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 a simple text so you can see that they are all working.

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

module.exports = { 
    index(req, res) { 
        res.send(`The image:index controller ${req.params.image_id}`); 
    }, 
    create(req, res) { 
        res.send('The image:create POST controller'); 
    }, 
    like (req, res) { 
        res.send('The image:like POST controller'); 
    }, 
    comment(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, which is set in the route when this controller function is executed. The params property was added to the request object via the urlencoded feature, which is a part of the body parser module!

Note that the controller currently doesn't require 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 into our configure.js file, right above the return app; line:

routes(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. We will need to comment out the redundant code that we just moved to routes, which is still present in server.js.

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:

First, we need to boot up with server.js

const express = require('express'); 
const config = require('./server/configure'); 
let app = express(); 
app.set('port', process.env.PORT || 3300); 
app.set('Views', `${ __dirname }/Views`); 
app = config(app); 
 
//commenting out following snippet that is not required 
// app.get('/', function(req, res){ 
//    res.send('Hello World'); 
// }); 
 
const server = app.listen(app.get('port'), ()=>{ 
    console.log(`Server up: http://localhost:${ app.get('port')}`); 
}); 

Next, we will configure the server with server/configure.js:

const path = require('path'), 
    routes = require('./routes'), 
    exphbs = require('express-handlebars'), 
    express = require('express'), 
    bodyParser = require('body-parser'), 
    cookieParser = require('cookie-parser'), 
    morgan = require('morgan'), 
    methodOverride = require('method-override'), 
    errorHandler = require('errorhandler'); 
 
module.exports = (app)=>{ 
  app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(methodOverride()); app.use(cookieParser('some-secret-value-here')); routes(app); app.use('/public/', express.static(path.join(__dirname,
'../public'))); if ('development' === app.get('env')) { app.use(errorHandler()); } return app; };

Then, we have our routes defined in server/routes.js:

const express = require('express'), 
    router = express.Router(), 
    home = require('../controllers/home'), 
    image = require('../controllers/image'); 
module.exports = (app)=>{ 
    router.get('/', home.index); 
    router.get('/images/:image_id', image.index); 
    router.post('/images', image.create); 
    router.post('/images/:image_id/like', image.like); 
    router.post('/images/:image_id/comment', image.comment); 
    app.use(router); 
}; 

Finally, we will define our controllers with controllers/home.js:

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

Furthermore, we will also define our controllers with controllers/image.js:

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

Let's fire up the server one last time and check if it's all working.

Execute the server.js node, and this time point your browser to http://localhost:3300. Now, you should be seeing some responses in the browser. Go to http://localhost:3300/images/testing123. You should see the following message on the screen:

 The image:index controller testing123 
..................Content has been hidden....................

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