• No results found

ORGANIZATION STRATEGIES

The first rule for any Node.JS application, including Express web apps, is to always be modular. Node.JS gives us a very powerful code organization strategy through the simple require

API.

For example, consider an application that has three distinct sections /blog, /pages, and /tags, each with other routes under their hierarchy. For example, /blog/search, /pages/list, or /tags/cloud.

A successful organization strategy would be to maintain a server.js file with the route map and then include the route handlers as modules blog.js, pages.js, and tags.js. First, you

define the dependencies and initialize the app, include middleware, and so on:

var express = require(‘express’) , blog = require(‘./blog’) , pages = require(‘./pages’) , tags = require(‘./tags’)

// initialize app

var app = express.createServer();

C H A P T E R 9 • Express

161

Then you define what I refer to as the route map, which is simply laying out all the URLs that you want to handle in a single place:

// blog routes app.get(‘/blog’, blog.home); app.get(‘/blog/search’, blog.search); app.post(‘/blog/create’, blog.create); // pages routes app.get(‘/pages’, pages.home); app.get(‘/pages/list’, pages.list); // tags routes app.get(‘/tags’, tags.home); app.get(‘/tags/search’, tags.search);

Then, for each specific file you would leverage exports. Consider the example for blog.js:

exports.home = function (req, res, next) { // home

};

exports.search = function (req, res, next) { // search functionality

};

Modules offer great flexibility. You could take this to a next level and divide modules by methods. For example:

exports.get = {};

exports.get.home = function (req, res, next) {}) exports.post = {};

exports.post.create = function (req, res, next) {})

The other way in which applications can be decoupled is what’s known as app mounting. You can export an entire Express app as a module (which you could also obtain from NPM), and

mount it to your existing application, making the routes match seamlessly.

Consider the example of an application that needs a blog. You can define a blog with all its routes /, /categories, and /search, and export that as blog.js:

var app = module.exports = express.createServer(); app.get(‘/’, function (req, res, next) {});

app.get(‘/categories’, function (req, res, next) {}); app.get(‘/search’, function (req, res, next) {});

Notice that the routes are defined in absolute terms, without a prefix. Then, in your main app, all you have to do is require it and pass it to app.use:

162

PA R T I I I • Web Development

app.use(require(‘./blog’));

With this, all the blog routes immediately become available to another application. In addition, you can set a prefix for them:

app.use (‘/blog’, require(‘./blog’));

Now the routes /blog/, /blog/categories, and /blog/search will seamlessly be

handled by the other express application, which can have its own completely separate set of dependencies, middleware, configuration, and more.

SUMMARY

In this chapter you learned how to leverage Express, the most popular Node.JS web framework.

The main benefit you’ll see from your usage and implementation of Express is that it’s simple, largely unopinionated but flexible, and it builds on top of other battle-tested and clean abstractions like Connect.

Unlike other web frameworks and libraries, Express can be easily molded to fit different needs, structures, and patterns. You learned how to use it with minimal implementation overhead in the first application example, just like the Node.JS Hello World.

As a matter of fact, you might have noticed that Express tries to stay close to the Node.JS core API and extend it, as opposed to creating a new world on top of it. That’s why route handlers still receive the native Node request and response objects, the same we received in the first HTTP server we wrote. You learned and appreciated the usefulness of these extensions, and how for example they make writing APIs that respond with JSON a breeze with res.send.

Finally, you learned how to put different pieces together to create maintainable code. Again, the main strategy of staying close to the Node.JS core APIs pays off: leveraging require is

Consider the following, for example:

GET /animals/index.html

GET /animals/mammals/index.html GET /animals/mammals/ferrets.html

With time, however, the web became more and more interactive. The traditional web that was about retrieving entire documents every time the user clicked is less common nowadays, especially with all the tools that HTML5 makes available. You can now create very sophisticated web applications that often have completely depre- cated desktop application counterparts, games, text editors, and more.

SO FAR, MOST website and web application developers are accustomed to communicating exclusively with a server by making HTTP requests that are followed by HTTP responses. The model of requesting a resource by specifying its URL, Content-Type, and other attributes

that you saw in previous chapters works well if you keep in mind the use case that the World Wide Web was crafted to solve. The web was created to deliver documents that were heavily interlinked to each other. URLs have paths because documents typically have hierarchies in file systems. And each level of hierarchy can contain indexes with hyperlinks.