11 min read

Node.js is a platform that supports various types of applications, but the most popular kind is the development of web applications. Node’s style of coding depends on the community to extend the platform through third-party modules; these modules are then built upon to create new modules, and so on. Companies and single developers around the globe are participating in this process by creating modules that wrap the basic Node APIs and deliver a better starting point for application development.

(For more resources related to this topic, see here.)

There are many modules to support web application development but none as popular as the Connect module. The Connect module delivers a set of wrappers around the Node.js low-level APIs to enable the development of rich web application frameworks. To understand what Connect is all about, let’s begin with a basic example of a basic Node web server. In your working folder, create a file named server.js, which contains the following code snippet:

var http = require('http');

http.createServer(function(req, res) {
res.writeHead(200, {
   'Content-Type': 'text/plain'
});
res.end('Hello World');
}).listen(3000);

console.log('Server running at http://localhost:3000/');

To start your web server, use your command-line tool, and navigate to your working folder. Then, run the node CLI tool and run the server.js file as follows:

$ node server

Now open http://localhost:3000 in your browser, and you’ll see the Hello World response.

So how does this work? In this example, the http module is used to create a small web server listening to the 3000 port. You begin by requiring the http module and use the createServer() method to return a new server object. The listen() method is then used to listen to the 3000 port. Notice the callback function that is passed as an argument to the createServer() method.

The callback function gets called whenever there’s an HTTP request sent to the web server. The server object will then pass the req and res arguments, which contain the information and functionality needed to send back an HTTP response. The callback function will then do the following two steps:

  1. First, it will call the writeHead() method of the response object. This method is used to set the response HTTP headers. In this example, it will set the Content-Type header value to text/plain. For instance, when responding with HTML, you just need to replace text/plain with html/plain.
  2. Then, it will call the end() method of the response object. This method is used to finalize the response. The end() method takes a single string argument that it will use as the HTTP response body. Another common way of writing this is to add a write() method before the end() method and then call the end() method, as follows:
    res.write('Hello World');
    res.end();

This simple application illustrates the Node coding style where low-level APIs are used to simply achieve certain functionality. While this is a nice example, running a full web application using the low-level APIs will require you to write a lot of supplementary code to support common requirements. Fortunately, a company called Sencha has already created this scaffolding code for you in the form of a Node module called Connect.

Meet the Connect module

Connect is a module built to support interception of requests in a more modular approach. In the first web server example, you learned how to build a simple web server using the http module. If you wish to extend this example, you’d have to write code that manages the different HTTP requests sent to your server, handles them properly, and responds to each request with the correct response.

Connect creates an API exactly for that purpose. It uses a modular component called middleware, which allows you to simply register your application logic to predefined HTTP request scenarios. Connect middleware are basically callback functions, which get executed when an HTTP request occurs. The middleware can then perform some logic, return a response, or call the next registered middleware. While you will mostly write custom middleware to support your application needs, Connect also includes some common middleware to support logging, static file serving, and more.

The way a Connect application works is by using an object called dispatcher. The dispatcher object handles each HTTP request received by the server and then decides, in a cascading way, the order of middleware execution. To understand Connect better, take a look at the following diagram:

The preceding diagram illustrates two calls made to the Connect application: the first one should be handled by a custom middleware and the second is handled by the static files middleware. Connect’s dispatcher initiates the process, moving on to the next handler using the next() method, until it gets to middleware responding with the res.end() method, which will end the request handling.

Express is based on Connect’s approach, so in order to understand how Express works, we’ll begin with creating a Connect application.

In your working folder, create a file named server.js that contains the following code snippet:

var connect = require('connect');
var app = connect();
app.listen(3000);

console.log('Server running at http://localhost:3000/');

As you can see, your application file is using the connect module to create a new web server. However, Connect isn’t a core module, so you’ll have to install it using NPM. As you already know, there are several ways of installing third-party modules. The easiest one is to install it directly using the npm install command. To do so, use your command-line tool, and navigate to your working folder. Then execute the following command:

$ npm install connect

NPM will install the connect module inside a node_modules folder, which will enable you to require it in your application file. To run your Connect web server, just use Node’s CLI and execute the following command:

$ node server

Node will run your application, reporting the server status using the console.log() method. You can try reaching your application in the browser by visiting http://localhost:3000. However, you should get a response similar to what is shown in the following screenshot:

Connect application’s empty response

What this response means is that there isn’t any middleware registered to handle the GET HTTP request. This means two things:

  • You’ve successfully managed to install and use the Connect module
  • It’s time for you to write your first Connect middleware

Connect middleware

Connect middleware is just JavaScript function with a unique signature. Each middleware function is defined with the following three arguments:

  • req: This is an object that holds the HTTP request information
  • res: This is an object that holds the HTTP response information and allows you to set the response properties
  • next: This is the next middleware function defined in the ordered set of Connect middleware

When you have a middleware defined, you’ll just have to register it with the Connect application using the app.use() method. Let’s revise the previous example to include your first middleware. Change your server.js file to look like the following code snippet:

var connect = require('connect');
var app = connect();

var helloWorld = function(req, res, next) {
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
};
app.use(helloWorld);

app.listen(3000);
console.log('Server running at http://localhost:3000/');

Then, start your connect server again by issuing the following command in your command-line tool:

$ node server

Try visiting http://localhost:3000 again. You will now get a response similar to that in the following screenshot:

Connect application’s response

Congratulations, you’ve just created your first Connect middleware!

Let’s recap. First, you added a middleware function named helloWorld(), which has three arguments: req, res, and next. In your middleware, you used the res.setHeader() method to set the response Content-Type header and the res.end() method to set the response text. Finally, you used the app.use() method to register your middleware with the Connect application.

Understanding the order of Connect middleware

One of Connect’s greatest features is the ability to register as many middleware functions as you want. Using the app.use() method, you’ll be able to set a series of middleware functions that will be executed in a row to achieve maximum flexibility when writing your application. Connect will then pass the next middleware function to the currently executing middleware function using the next argument. In each middleware function, you can decide whether to call the next middleware function or stop at the current one. Notice that each Connect middleware function will be executed in first-in-first-out (FIFO) order using the next arguments until there are no more middleware functions to execute or the next middleware function is not called.

To understand this better, we will go back to the previous example and add a logger function that will log all the requests made to the server in the command line. To do so, go back to the server.js file and update it to look like the following code snippet:

var connect = require('connect');
var app = connect();

var logger = function(req, res, next) {
console.log(req.method, req.url);

next();
};

var helloWorld = function(req, res, next) {
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
};

app.use(logger);
app.use(helloWorld);
app.listen(3000);

console.log('Server running at http://localhost:3000/');

In the preceding example, you added another middleware called logger(). The logger() middleware uses the console.log() method to simply log the request information to the console. Notice how the logger() middleware is registered before the helloWorld() middleware. This is important as it determines the order in which each middleware is executed. Another thing to notice is the next() call in the logger() middleware, which is responsible for calling the helloWorld() middleware. Removing the next() call would stop the execution of middleware function at the logger() middleware, which means that the request would hang forever as the response is never ended by calling the res.end() method.

To test your changes, start your connect server again by issuing the following command in your command-line tool:

$ node server

Then, visit http://localhost:3000 in your browser and notice the console output in your command-line tool.

Mounting Connect middleware

As you may have noticed, the middleware you registered responds to any request regardless of the request path. This does not comply with modern web application development because responding to different paths is an integral part of all web applications. Fortunately, Connect middleware supports a feature called mounting, which enables you to determine which request path is required for the middleware function to get executed. Mounting is done by adding the path argument to the app.use() method. To understand this better, let’s revisit our previous example. Modify your server.js file to look like the following code snippet:

var connect = require('connect');
var app = connect();

var logger = function(req, res, next) {
console.log(req.method, req.url);

next();
};

var helloWorld = function(req, res, next) {
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
};

var goodbyeWorld = function(req, res, next) {
res.setHeader('Content-Type', 'text/plain');
res.end('Goodbye World');
};

app.use(logger);
app.use('/hello', helloWorld);
app.use('/goodbye', goodbyeWorld);
app.listen(3000);

console.log('Server running at http://localhost:3000/');

A few things have been changed in the previous example. First, you mounted the helloWorld() middleware to respond only to requests made to the /hello path. Then, you added another (a bit morbid) middleware called goodbyeWorld() that will respond to requests made to the /goodbye path. Notice how, as a logger should do, we left the logger() middleware to respond to all the requests made to the server. Another thing you should be aware of is that any requests made to the base path will not be responded by any middleware because we mounted the helloWorld() middleware to a specific path.

Connect is a great module that supports various features of common web applications. Connect middleware is super simple as it is built with a JavaScript style in mind. It allows the endless extension of your application logic without breaking the nimble philosophy of the Node platform. While Connect is a great improvement over writing your web application infrastructure, it deliberately lacks some basic features you’re used to having in other web frameworks. The reason lies in one of the basic principles of the Node community: create your modules lean and let other developers build their modules on top of the module you created. The community is supposed to extend Connect with its own modules and create its own web infrastructures. In fact, one very energetic developer named TJ Holowaychuk, did it better than most when he released a Connect-based web framework known as Express.

Summary

In this article, you learned about the basic principles of Node.js web applications and discovered the Connect web module. You created your first Connect application and learned how to use middleware functions.

To learn more about Node.js and Web Development, the following books published by Packt Publishing (https://www.packtpub.com/) are recommended:

  • Node.js Design Patterns (https://www.packtpub.com/web-development/nodejs-design-patterns)
  • Web Development with MongoDB and Node.js (https://www.packtpub.com/web-development/web-development-mongodb-and-nodejs)

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here