Chapter 4. HTTP Servers and Clients – A Web Application's First Steps

Now that you've learned about Node.js modules, it's time to put this knowledge to work in building a simple Node.js web application. In this chapter, we'll keep to a simple application, enabling us to explore three different application frameworks for Node.js. In later chapters, we'll build some more complex applications, but before we can walk, we must learn to crawl.

We will cover the following topics in this chapter:

  • EventEmitters
  • Listening to HTTP events and the HTTP Server object
  • HTTP request routing
  • ES-2015 template strings
  • Building a simple web application with no frameworks
  • The Express application framework
  • Express middleware functions
  • How to deal with computationally intensive code
  • The HTTP Client object
  • Creating a simple REST service with Express

Sending and receiving events with EventEmitters

EventEmitters are one of the core idioms of Node.js. Many of the core modules are EventEmitters, and also EventEmitters make an excellent skeleton to implement asynchronous programming. EventEmitters have nothing to do with web application development, but they are so much part of the woodwork that you may skip over their existence. It is with the HTTP classes that we will get our first taste of EventEmitters.

In this chapter, we'll work with the HTTPServer and HTTPClient objects. Both of them are subclasses of EventEmitter and rely on it to send events for each step of the HTTP protocol. Understanding EventEmitter will help you understand not only these objects but many other objects in Node.js.

The EventEmitter object is defined in the events module of Node.js. Directly using the EventEmitter class means performing require('events'). In most cases, you won't require this module, but there are cases where the program needs to implement a subclass of EventEmitter.

Create a file named pulser.js that will contain the following code. It shows both sending as well as receiving events while directly using the EventEmitter class:

var events = require('events');
var util   = require('util');
// Define the Pulser object

function Pulser() {
    events.EventEmitter.call(this);
}
util.inherits(Pulser, events.EventEmitter);

Pulser.prototype.start = function() {
    setInterval(() => {
        util.log('>>>> pulse');
        this.emit('pulse');
        util.log('<<<< pulse');
    }, 1000);
};

This defines a Pulser class, which inherits from EventEmitter (using util.inherits). Its purpose is to send timed events, once a second, to any listeners. The start method uses setInterval to kick off repeated callback execution, scheduled for every second, and call emit to send the pulse events to any listeners.

This much could be the starting point of a general-purpose module to send events at a given interval. Instead, we're just exploring how EventEmitter works.

Now, let's see how to use the Pulser object by adding the following code to pulser.js:

// Instantiate a Pulser object
var pulser = new Pulser();
// Handler function
pulser.on('pulse', () => {
    util.log('pulse received');
});
// Start it pulsing
pulser.start();

Here we create a Pulser object and consume its pulse events. Calling pulser.on('pulse') sets up connections for the pulse events to invoke the callback function. It then calls the start method to get the process going.

Enter this into a file and name the file pulser.js. When you run it, you should see the following output:

$ node pulser.js 
19 Apr 16:58:04 - >>>> pulse
19 Apr 16:58:04 - pulse received
19 Apr 16:58:04 - <<<< pulse
19 Apr 16:58:05 - >>>> pulse
19 Apr 16:58:05 - pulse received
19 Apr 16:58:05 - <<<< pulse
19 Apr 16:58:06 - >>>> pulse
19 Apr 16:58:06 - pulse received
19 Apr 16:58:06 - <<<< pulse

The EventEmitter theory

The EventEmitter event has many names, and it can be anything that makes sense to you. You can define as many event names as you like. Event names are defined simply by calling .emit with the event name. There's nothing formal to do, no registry of event names. Simply making a call to .emit is enough to define an event name.

Note

By convention, the event name error indicates errors.

An object sends events using the .emit function. Events are sent to any listeners that have registered to receive events from the object. The program registers to receive an event by calling that object's .on method, giving the event name and an event handler function.

Often, it is required to send data along with an event. To do so, simply add the data as arguments to the .emit call, as follows:

this.emit('eventName', data1, data2, ..);

When the program receives that event, the data appears as arguments to the callback function. Your program would listen to such an event as follows:

emitter.on('eventName', (data1, data2, ..) => {
  // act on event
});

There is no handshaking between event receivers and the event sender. That is, the event sender simply goes on with its business, and it gets no notifications about any events received, any action taken, or any error occurred.

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

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