Node js24hrs
Node js24hrs
Node.js
Editor-in-Chief
Mark Taub
Acquisitions Editor
Laura Lewin
Development
Editor
Sheri Cain
Managing Editor
Kristy Hart
Project Editor
Anne Goebel
Copy Editor
Geneil Breeze
Indexer
Tim Wright
Trademarks
Proofreader
Sarah Kearns
All terms mentioned in this book that are known to be trademarks or service marks have been
appropriately capitalized. Sams Publishing cannot attest to the accuracy of this information. Use
of a term in this book should not be regarded as affecting the validity of any trademark or service
mark.
Bulk Sales
Sams Publishing offers excellent discounts on this book when ordered in quantity for bulk purchases or special sales. For more information, please contact
U.S. Corporate and Government Sales
1-800-382-3419
[email protected]
For sales outside of the U.S., please contact
International Sales
[email protected]
Technical Editor
Remy Sharp
Publishing
Coordinator
Olivia Basegio
Interior Designer
Gary Adair
Cover Designer
Anne Jones
Senior Compositor
Gloria Schurick
Contents at a Glance
Introduction ............................................................................................... 1
iv
Table of Contents
Introduction
15
vi
27
41
59
Contents
vii
73
What Is Express?.................................................................................................. 73
Why Use Express? ................................................................................................ 73
Installing Express ................................................................................................ 74
Creating a Basic Express Site .............................................................................. 74
Exploring Express ................................................................................................ 76
Introducing Jade .................................................................................................. 77
Summary ............................................................................................................. 89
Q&A ..................................................................................................................... 89
Workshop............................................................................................................. 90
Exercises ............................................................................................................... 90
HOUR 7: More on Express
91
103
viii
Workshop........................................................................................................... 132
Exercises ............................................................................................................. 132
135
151
169
Contents
ix
189
213
237
265
291
305
Contents
xi
317
333
345
xii
361
381
399
Contents
xiii
417
Index
435
Dedication
This book is dedicated to my wife, Kirsten.
Without your support, this book would not have been possible.
Acknowledgments
Thanks to Trina MacDonald and the team at Pearson for giving me the chance to write this
book. Your encouragement and guidance was invaluable.
Thanks to Remy Sharp, the technical editor on the book. You picked up numerous mistakes
and oversights over the course of the reviews. I owe you a beer! Any mistakes left in the
book are, of course, my own.
Thanks to my colleagues at pebble {code}. From the start, you were right behind me writing
the book. I am grateful for the flexibility around big projects that allowed me to finish this
book.
Mail:
Reader Services
Visit our website and register this book at informit.com/register for convenient access to any
updates, downloads, or errata that might be available for this book.
Introduction
The ability to use JavaScript on the server allows developers who are familiar with JavaScript to
add server-side development to their curriculum vitae. Node.js is much more than that, though.
It rethinks network programming in the context of the modern web where an application may
rely on reading and writing data from many different places and may have millions of concurrent users.
JavaScript is often seen as a toy language by developers who have traditional computer science
degrees. But, JavaScript has survived numerous challenges and is now integral to the direction
of the web both in the browser and with Node.js on the server-side too. There has never been a
better time to write JavaScript, especially on the server!
Node.js represents a development platform that can respond to creating applications for the
modern web. This includes
Real-time applications
Multiplayer games
Single-page applications
JSON-based APIs
It is focused on speed and scalability and can handle thousands of concurrent users without
needing expensive hardware. The Node.js project recently became the most watched project on
GitHub and is now being used by companies like eBay, LinkedIn, and Microsoft.
Node.js is much more than JavaScript on the server. It is a fully featured network programming
platform for responding to the demands of modern web programming.
Introduction
Code Examples
Each hour in this book comes with several code examples. These examples help you learn
about Node.js as much as the text in this book. You can download this code at http://bit.ly/
nodejsbook-examples, and they are also available as a GitHub repository at https://github.com/
shapeshed/nodejsbook.io.examples.
Finally, the following icons introduce other pertinent information used in the book:
BY THE WAY
By the Way presents interesting pieces of information related to the surrounding discussion.
WATCH OUT
Watch Out! advises you about potential problems and helps you steer clear of disaster.
HOUR 14
Streaming APIs
In Hour 13, A Socket.IO Chat Server, you learned how to create a chat server with Socket.IO
and Express. This involved sending data from clients (or browsers) to the Socket.IO server and
then broadcasting it out to other clients. In this hour, you learn how Node.js and Socket.IO can
be used to consume data directly from the web and then broadcast the data to connected clients.
You will work with Twitters streaming Application Programming Interface (API) and push data
out to the browser in real-time.
With Twitters standard API, the process for getting data is as follows:
238
239
FIGURE 14.1
Creating a Twitter application
Once you create your application, you need to generate an access token and an accesstoken secret to gain access to the API from your application.
3. At the bottom of the Details tab is a Create My Access Token button (see Figure 14.2). Click
this button to create an access token and an access token secret.
240
FIGURE 14.2
Requesting an access token
4. When the page refreshes, you see that values have been added for access token and access
token secret (see Figure 14.3). Now, you are ready to start using the API!
241
FIGURE 14.3
A successful creation of an access token
BY THE WAY
242
{
"name":"socket.io-twitter-example",
"version":"0.0.1",
"private":true,
"dependencies":{
"express":"2.5.4",
"ntwitter":"0.2.10"
}
}
The ntwitter module uses OAuth to authenticate you, so you must provide four pieces of information:
Consumer key
Consumer secret
Access token key
Access token secret
If you requested these when you were setting up the application in the Twitter Developers website, these will be available on the Details page for your application. If you did not request them
when you set up the application, you need to do so now under the Details tab. Once you have
the keys and secrets, you can create a small Express server to connect to Twitters streaming API:
var app = require('express').createServer(),
twitter = require('ntwitter');
app.listen(3000);
var twit = new twitter({
consumer_key: 'YOUR_CONSUMER_KEY',
consumer_secret: 'YOUR_CONSUMER_SECRET',
access_token_key: 'YOUR_ACCESS_TOKEN_KEY',
access_token_secret: 'YOUR_ACCESS_TOKEN_KEY'
});
Of course, you need to remember to replace the values in the example with your actual values.
This is all you need to start interacting with Twitters API! In this example, you answer the question, Is there more love or hate in the world? by using real-time data from Twitter. You request
tweets from Twitters streaming API that mention the words love or hate and perform a
small amount of analysis on the data to answer the question. The ntwitter module makes it easy
to request this data:
243
This requests data from the 'statuses/filter' endpoint that allows developers to track tweets
by keyword, location, or specific users. In this case, we are interested in the keywords 'love'
and 'hate'. The Express server opens a connection to the API server and listens for new data
being received. Whenever a new data item is received, it writes the data to the console. In other
words, you can see the stream live for the keywords love and hate in the terminal.
TRY IT YOURSELF
If you have downloaded the code examples for this book, this code is hour14/example01.
To stream data from Twitter, follow these steps:
1. Create a new folder called express_twitter.
2. Within the express_twitter folder, create a new file called package.json and add the following content to declare ntwitter and Express as dependencies:
{
"name":"socket.io-twitter-example",
"version":"0.0.1",
"private":true,
"dependencies":{
"express":"2.5.4",
"ntwitter":"0.2.10"
}
}
3. Within the express_twitter folder, create a new file called app.js with the following content.
Remember to replace the keys and secrets with your own:
var app = require('express').createServer(),
twitter = require('ntwitter');
app.listen(3000);
var twit = new twitter({
consumer_key: 'YOUR_CONSUMER_KEY',
consumer_secret: 'YOUR_CONSUMER_SECRET',
access_token_key: 'YOUR_ACCESS_TOKEN_KEY',
access_token_secret: 'YOUR_ACCESS_TOKEN_KEY'
244
});
twit.stream('statuses/filter', { track: ['love', 'hate'] }, function(stream) {
stream.on('data', function (data) {
console.log(data);
});
});
6. Watch the terminal; you should see data being received from Twitters streaming API (see
Figure 14.4). There is a lot of data, so expect it to move fast!
7. Kill the server pressing Ctrl+C in the terminal.
FIGURE 14.4
Streaming data to the terminal
245
notation to retrieve the data that you are interested in. So, if you wanted to view the screen
name of the user along with the tweet, this can be easily achieved:
twit.stream('statuses/filter', { track: ['love', 'hate'] }, function(stream) {
stream.on('data', function (data) {
console.log(data.user.screen_name + ': ' + data.text);
});
});
Full documentation on the structure of the data received from Twitter is available on the documentation for the status element. This can be viewed online at https://dev.twitter.com/docs/
api/1/get/statuses/show/%3Aid. Under the section, Example Request, you can see the data
structure for a status response. Using dot notation on the data object returned from Twitter, you
are able to access any of these data points. For example, if you want the URL for the user, you
can use data.user.url. Here is the full data available for the user who posted the tweet:
"user": {
"profile_sidebar_border_color": "eeeeee",
"profile_background_tile": true,
"profile_sidebar_fill_color": "efefef",
"name": "Eoin McMillan ",
"profile_image_url": "http://a1.twimg.com/profile_images/1380912173/Screen_
shot_2011-06-03_at_7.35.36_PM_normal.png",
"created_at": "Mon May 16 20:07:59 +0000 2011",
"location": "Twitter",
"profile_link_color": "009999",
"follow_request_sent": null,
"is_translator": false,
"id_str": "299862462",
"favourites_count": 0,
"default_profile": false,
"url": "http://www.eoin.me",
"contributors_enabled": false,
"id": 299862462,
"utc_offset": null,
"profile_image_url_https": "https://si0.twimg.com/profile_images/1380912173/
Screen_shot_2011-06-03_at_7.35.36_PM_normal.png",
"profile_use_background_image": true,
"listed_count": 0,
"followers_count": 9,
"lang": "en",
"profile_text_color": "333333",
"protected": false,
"profile_background_image_url_https": "https://si0.twimg.com/images/themes/
theme14/bg.gif",
"description": "Eoin's photography account. See @mceoin for tweets.",
"geo_enabled": false,
"verified": false,
246
"profile_background_color": "131516",
"time_zone": null,
"notifications": null,
"statuses_count": 255,
"friends_count": 0,
"default_profile_image": false,
"profile_background_image_url": "http://a1.twimg.com/images/themes/theme14/
bg.gif",
"screen_name": "imeoin",
"following": null,
"show_all_inline_media": false
}
There is much more information available with each response, including geographic coordinates, whether the tweet was retweeted, and more.
TRY IT YOURSELF
If you have downloaded the code examples for this book, this code is hour14/example02.
To parse data from Twitter, follow these steps:
1. Create a new folder called parsing_twitter_data.
2. Within the parsing_twitter_data folder, create a new file called package.json and add the
following content to declare ntwitter and Express as dependencies:
{
"name":"socket.io-twitter-example",
"version":"0.0.1",
"private":true,
"dependencies":{
"express":"2.5.4",
"ntwitter":"0.2.10"
}
}
3. Within the express_twitter folder, create a new file called app.js with the following content.
Remember to replace the keys and secrets with your own:
var app = require('express').createServer(),
twitter = require('ntwitter');
app.listen(3000);
var twit = new twitter({
consumer_key: 'YOUR_CONSUMER_KEY',
247
consumer_secret: 'YOUR_CONSUMER_SECRET',
access_token_key: 'YOUR_ACCESS_TOKEN_KEY',
access_token_secret: 'YOUR_ACCESS_TOKEN_KEY'
});
twit.stream('statuses/filter', { track: ['love', 'hate'] }, function(stream) {
stream.on('data', function (data) {
console.log(data.user.screen_name + ': ' + data.text);
});
});
6. Watch the terminal; you should see that now only the screen name of the user and the
tweet are displayed (see Figure 14.5).
7. Kill the server by pressing Ctrl+C in the terminal.
FIGURE 14.5
Parsing data received from Twitter
248
IO server and then broadcast to connected clients. To use Socket.IO, it must first be added as a
dependency in the package.json file:
{
"name":"socket.io-twitter-example",
"version":"0.0.1",
"private":true,
"dependencies":{
"express":"2.5.4",
"ntwitter":"0.2.10",
"socket.io":"0.8.7"
}
}
Then, Socket.IO must be required in the main server file and instructed to listen to the Express
server. This is exactly the same as the examples you worked through in Hours 12 and 13:
var app = require('express').createServer(),
twitter = require('ntwitter'),
io = require('socket.IO').listen(app);
The streaming API request can now be augmented to push the data out to any connected
Socket.IO clients whenever a new data event is received:
twit.stream('statuses/filter', { track: ['love', 'hate'] }, function(stream) {
stream.on('data', function (data) {
io.sockets.volatile.emit('tweet', {
user: data.user.screen_name,
text: data.text
});
});
});
Instead of logging the data to the console, you are now doing something useful with the data
by pushing it out to connected clients. A simple JSON structure is created to hold the name of
the user and the tweet. If you want to send more information to the browser, you could simply
extend the JSON object to hold other attributes.
You may have noticed that, instead of using io.sockets.emit as you did in Hours 12 and 13,
you are now using io.sockets.volatile.emit. This is an additional method provided by
Socket.IO for scenarios where certain messages can be dropped. This may be down to network
issues or a user being in the middle of a request-response cycle. This is particularly the case
where high volumes of messages are being sent to clients. By using the volatile method, you
can ensure that your application will not suffer if a certain client does not receive a message. In
other words, it does not matter whether a client does not receive a message.
The Express server is also instructed to serve a single HTML page so that the data can be viewed
in a browser.
249
On the client side (or browser), some simple client-side JavaScript is added to the index.html file
to listen for new tweets being sent to the browser and display them to the user. The full HTML
file is available in the following example:
<ul class="tweets"></ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></
script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
jQuery(function ($) {
var tweetList = $('ul.tweets');
socket.on('tweet', function (data) {
tweetList
.prepend('<li>' + data.user + ': ' + data.text + '</li>');
});
});
</script>
An empty unordered list is added to the DOM (Document Object Model), and this is filled with
a new list item containing the screen name of the user and the tweet each time a new tweet is
received. This uses jQuerys prepend() method to insert data received into a list item within the
unordered list. This has the effect of creating a stream on the page.
Now, whenever Socket.IO pushes a new tweet event out, the browser receives it and writes it
to the page immediately. Instead of viewing the stream of tweets in a terminal, it can now be
viewed in the browser.
TRY IT YOURSELF
If you have downloaded the code examples for this book, this code is hour14/example03.
Heres how to stream Twitter data to a browser:
1. Create a new folder called socket.io-twitter-example.
2. Within the socket.io-twitter-example folder, create a new file called package.json and add
the following content to declare ntwitter, Express, and Socket.IO as dependencies:
{
"name":"socket.io-twitter-example",
"version":"0.0.1",
"private":true,
"dependencies":{
250
"express":"2.5.4",
"ntwitter":"0.2.10",
"socket.io":"0.8.7"
}
}
3. Within the socket.io-twitter-example folder, create a new file called app.js with the following
content. Remember to replace the keys and secrets with your own:
var app = require('express').createServer(),
twitter = require('ntwitter'),
io = require('socket.io').listen(app);
app.listen(3000);
var twit = new twitter({
consumer_key: 'YOUR_CONSUMER_KEY',
consumer_secret: 'YOUR_CONSUMER_SECRET',
access_token_key: 'YOUR_ACCESS_TOKEN_KEY',
access_token_secret: 'YOUR_ACCESS_TOKEN_KEY'
});
twit.stream('statuses/filter', { track: ['love', 'hate'] }, function(stream) {
stream.on('data', function (data) {
io.sockets.volatile.emit('tweet', {
user: data.user.screen_name,
text: data.text
});
});
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
4. Within the Socket.IO-twitter-example, create a file called index.html and add the following
content:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Socket.IO Twitter Example</title>
</head>
<body>
<h1>Socket.IO Twitter Example</h1>
<ul class="tweets"></ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.
min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
jQuery(function ($) {
var tweetList = $('ul.tweets');
socket.on('tweet', function (data) {
tweetList
.prepend('<li>' + data.user + ': ' + data.text + '</li>');
});
});
</script>
</body>
</html>
FIGURE 14.6
Streaming tweets to the browser
251
252
Whenever new data is received from the API, the love counter will be incremented if the word
love is found and so on. JavaScripts indexOf() string function can be used to look for words
within a tweet and provides a simple way to analyze the content of tweets:
twit.stream('statuses/filter', { track: ['love', 'hate'] }, function(stream) {
stream.on('data', function (data) {
var text = data.text.toLowerCase();
if (text.indexOf('love') !== -1) {
love++
total++
}
if (text.indexOf('hate') !== -1) {
hate++
total++
}
});
});
253
Because some tweets may contain both love and hate, the total is incremented each time a
word is found. This means that the total counter represents the total number of times love or
hate was mentioned in a tweet rather than the total number of tweets.
Now that the application is maintaining a count of the occurrences of words, this data can be
added to the tweet emitter and pushed to connected clients in real-time. Some simple calculation
is also used to send the values as a percentage of the total number of tweets:
io.sockets.volatile.emit('tweet', {
user: data.user.screen_name,
text: data.text,
love: (love/total)*100,
hate: (hate/total)*100
});
On the client side, by using an unordered list and some client-side JavaScript, the browser can
receive the data and show it to users. Before any data is received from the server, the values are
set to zero:
<ul class="percentage">
<li class="love">0</li>
<li class="hate">0</li>
</ul>
Finally, a client-side listener can be added to receive the tweet event and replace the percentage
values with the ones received from the server. By starting the server and opening the browser,
you can now answer the question!
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></
script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
jQuery(function ($) {
var tweetList = $('ul.tweets'),
loveCounter = $('li.love'),
hateCounter = $('li.hate');
socket.on('tweet', function (data) {
tweetList
.prepend('<li>' + data.user + ': ' + data.text + '</li>');
loveCounter
.text(data.love + '%');
hateCounter
.text(data.hate + '%');
});
});
</script>
254
TRY IT YOURSELF
If you have downloaded the code examples for this book, this code is hour14/example04.
To analyze data from Twitters streaming API, follow these steps:
1. Create a new folder called percentages.
2. Within the percentages folder, create a new file called package.json and add the following
content to declare ntwitter, Express, and Socket.IO as dependencies:
{
"name":"socket.io-twitter-example",
"version":"0.0.1",
"private":true,
"dependencies":{
"express":"2.5.4",
"ntwitter":"0.2.10",
"socket.io":"0.8.7"
}
}
3. Within the percentages folder, create a new file called app.js with the following content.
Remember to replace the keys and secrets with your own:
var app = require('express').createServer(),
twitter = require('ntwitter'),
io = require('socket.io').listen(app),
love = 0,
hate = 0,
total = 0;
app.listen(3000);
var twit = new twitter({
consumer_key: 'YOUR_CONSUMER_KEY',
consumer_secret: 'YOUR_CONSUMER_SECRET',
access_token_key: 'YOUR_ACCESS_TOKEN_KEY',
access_token_secret: 'YOUR_ACCESS_TOKEN_KEY'
});
twit.stream('statuses/filter', { track: ['love', 'hate'] }, function(stream) {
stream.on('data', function (data) {
var text = data.text.toLowerCase();
if (text.indexOf('love') !== -1) {
love++
total++
}
if (text.indexOf('hate') !== -1) {
hate++
total++
}
io.sockets.volatile.emit('tweet', {
user: data.user.screen_name,
text: data.text,
love: (love/total)*100,
hate: (hate/total)*100
});
});
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
4. Within the percentages folder, create a file called index.html and add the following
content:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Socket.IO Twitter Example</title>
</head>
<body>
<h1>Socket.IO Twitter Example</h1>
<ul class="percentage">
<li class="love">0</li>
<li class="hate">0</li>
</ul>
<ul class="tweets"></ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.
min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
jQuery(function ($) {
var tweetList = $('ul.tweets'),
loveCounter = $('li.love'),
hateCounter = $('li.hate');
socket.on('tweet', function (data) {
tweetList
.prepend('<li>' + data.user + ': ' + data.text + '</li>');
loveCounter
.text(data.love + '%');
hateCounter
255
256
.text(data.hate + '%');
});
});
</script>
</body>
</html>
FIGURE 14.7
Dynamically updating percentage values
257
Some CSS can then be added to the head of the HTML document that makes the unordered list
look like a bar graph. The list items represent the bars with colors of pink to represent love and
black to represent hate:
<style>
ul.percentage
ul.percentage
ul.percentage
ul.percentage
ul.percentage
</style>
{ width: 100% }
li { display: block; width: 0 }
li span { float: right; display: block}
li.love { background: #ff0066; color: #fff}
li.hate { background: #000; color: #fff}
Finally, some client-side JavaScript allows the bars (the list items) to be resized dynamically
based on the percentage values received from the server:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></
script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
jQuery(function ($) {
var tweetList = $('ul.tweets'),
loveCounter = $('li.love'),
hateCounter = $('li.hate'),
loveCounterPercentage = $('li.love span'),
hateCounterPercentage = $('li.hate span');
socket.on('tweet', function (data) {
loveCounter
258
Whenever a new tweet event is received from Socket.IO, the bar graph is updated by dynamically setting the CSS width of the list items with the percentage values received from the server.
This has the effect of adjusting the graph each time a new tweet event is received. You have created a real-time graph!
TRY IT YOURSELF
If you have downloaded the code examples for this book, this code is hour14/example05.
Follow these steps to visualize real-time data:
1. Create a new folder called realtime_graph.
2. Within the realtime_graph folder, create a new file called package.json and add the following content to declare ntwitter, Express, and Socket.IO as dependencies:
{
"name":"socket.io-twitter-example",
"version":"0.0.1",
"private":true,
"dependencies":{
"express":"2.5.4",
"ntwitter":"0.2.10",
"socket.io":"0.8.7"
}
}
3. Within the realtime_graph folder, create a new file called app.js with the following content.
Remember to replace the keys and secrets with your own:
var app = require('express').createServer(),
twitter = require('ntwitter'),
io = require('socket.io').listen(app),
love = 0,
hate = 0,
259
total = 0;
app.listen(3000);
var twit = new twitter({
consumer_key: 'YOUR_CONSUMER_KEY',
consumer_secret: 'YOUR_CONSUMER_SECRET',
access_token_key: 'YOUR_ACCESS_TOKEN_KEY',
access_token_secret: 'YOUR_ACCESS_TOKEN_KEY'
});
twit.stream('statuses/filter', { track: ['love', 'hate'] }, function(stream) {
stream.on('data', function (data) {
var text = data.text.toLowerCase();
if (text.indexOf('love') !== -1) {
love++
total++
}
if (text.indexOf('hate') !== -1) {
hate++
total++
}
io.sockets.volatile.emit('tweet', {
user: data.user.screen_name,
text: data.text,
love: (love/total)*100,
hate: (hate/total)*100
});
});
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
4. Within the realtime_graph folder, create a file called index.html and add the following
content:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Socket.IO Twitter Example</title>
<style>
ul.percentage { width: 100% }
260
261
FIGURE 14.8
A real-time graph
The application that you created provides a visual representation of whether there is more love
than hate in the world based on real-time data from Twitter. Granted, this is totally unscientific,
but it showcases the capabilities of Node.js and Socket.IO to receive large amounts of data and
push it out to the browser. With a little more CSS work, the application can be styled to look
better (see Figure 14.9).
262
FIGURE 14.9
The finished application with additional styling
If you want to run this example yourself, this version is available in the code for this book as
hour14/example06.
Summary
In this hour, you answered a fundamental question about human nature using Node.js, Twitter,
and Socket.IO. Not bad for an hours work! At the time of writing, there is more love in the
world, so if you take nothing else from this hour, rejoice! You learned how a Node.js server
can receive large amounts of data from a third-party service and push it out to the browser in
real-time using Socket.IO. You saw how to manipulate the data to extract meaning from it and
perform simple calculations on the data to extract percentage values. Finally, you added some
client-side JavaScript to receive the data and create a real-time graph. This hour showcased
many of the strengths of Node.js, including the ease that data can be sent between the server
and browser, the ability to process large amounts of data, and the strong support for networking.
Workshop
263
Q&A
Q. Are there other streaming APIs that I can use to create applications like this?
A. Yes. An increasing number of streaming APIs is becoming available to developers. At the
time of writing, some APIs of interest include Campfire, Salesforce, Datasift, and Apigee,
with many more expected to be created.
Q. How accurate is this data?
A. Not very. This data is based on the statuses/filter method from Twitters streaming API.
More information about what goes into this feed is available at https://dev.twitter.com/
docs/streaming-api/methods. In short, do not base any anthropological studies on it.
Q. Can I save this data somewhere?
A. The application created in this hour does not persist data anywhere, so if the server is
stopped, the counters and percentages are reset. Clearly, the longer that data can be collected, the more accurate the results. The application could be extended to store the counters with a data store that can handle high volumes of writes, like Redis. This is outside
the scope of this hour, though!
Workshop
This workshop contains quiz questions and exercises to help cement your learning in this hour.
Quiz
1. What is different about a streaming API?
2. What is OAuth?
3. Why is Node.js a good fit for working with streaming APIs?
Quiz Answers
1. A streaming API keeps the connection between client and server open and is able to push
new data to the client when it becomes available. This enables applications to become realtime as data is pushed to the client as soon as it is available.
2. OAuth is a way for applications to grant access to data without exposing user credentials.
Authorization is granted on a per-application basis and can be revoked at any time. If you
have connected your Twitter account with any other services, you may be familiar with allowing other services to access your data. OAuth is used to achieve this.
3. As Node.js is designed around evented I/O, it can respond very well to new data being
received from a streaming API. It can handle large amounts of data without needing huge
amounts of memory. Because Node.js is JavaScript, it is easy to communicate with clients
like browsers that understand JSON. Node.js is able to receive, process, and transmit large
numbers of data events without needing many machines to process it on.
264
Exercises
1. Amend the example available in this books code examples, as hour14/example02, to
display the users real name and URL. Consult the data structure earlier in this hour
to understand which attributes you need for this.
2. Amend the server to receive data from Twitters streaming API based on some keywords
that you are interested in. If there are more than two keywords, update the application to
show more than two bars on the graph.
3. Think about how you could create an application to provide visualizations of different
streaming Twitter datasets. Remember that you can limit your query by location, certain
users, and keywords. Some examples to get you started:
Do people talk more about beer or wine in London?
How often do famous people use the words me or you?
Are the Beatles more popular than the Rolling Stones?
Index
Backbone.js, 417-418
operability with Node.js,
418-422
records, creating, 428-430
views, 425-429
BDD (Behavior Driven
Development), 159-167
bi-directional data, 202-208
binary data, 333-334
converting to text, 334-335
bits, 106, 334
Blagovest, Dachev, 20
blocking code, 50-53
Brandzeg, Eirik, 21
436
CoffeeScript, 361-363
converting
classes, 371-376
comparisons, 368
conditions, 368
debugging, 376-377
copying, 341
Heredocs, 371-372
creating
inheritance, 371-376
installing, 362-364
loops, 368-370
HTML clients, 68
objects, 371
strings, 370
callbacks, 41-49
in chat server application,
221-225
Comet, 190
lovehateometer, 252-262
CommonJS, 384
modules, 381
scripts, 297
cubing numbers
callbacks, 221-225
messaging, 229-231
compiling CoffeeScript to
JavaScript, 365-364
killing, 308-309
concurrency, 37
Jade, 84-86
connecting
code execution, 34
callbacks, 41-45
synchronous code, 50-53
cURL, 62-65
custom headers, adding with
Middleware, 404
CoffeeScript, 368
client-side JavaScript, 8
in JavaScript, 367
Cucumber, 29
conditions
in CoffeeScript, 366
to MongDB, 113-114
Socket.IO client and server,
191-194
D
Dahl, Ryan, 7
databases, 107-109
MongoDB, 109-131
connecting to, 113-114
documents, defining,
edit view, 120-125
folders
variables, 82
installing, 110-112
Twitter Bootstrap, 116-117
437
NoSQL, 109
encoding, 335-334
parameters, 94-96
buffers, 338-339
event-driven programming, 34
routing, 91
events
in CoffeeScript, 376-377
organization, 96-97
emitting, 321-320
Sinatra, 74
firing, 318-320
defining
HTTP, 320-322
mixins, 87-89
listeners, 325-327
structure, 75-77
MongoDB documents,
Express, 73
files
Nodester, 180-183
installing, 74
Jade, 77-89
conditions, 84-86
includes, 87-88
inline JavaScript, 84
loops, 83-85
mixins, 87-89
folders
Express, 75-77
in modules, 384-385
438
MongoDB, 110-112
Node.js, 9-10
clients, 68
functions
events, 320-322
input, 29-32
callbacks, 41-49
-g flag, 74
organization, 96-97
GET requests, 91
parameters, 94-96
specifying, 92-93
verbs, 91
GitHub, 391-392
global module installation, 22
J-K
Jade, 77-89
conditions, 84-86
includes, 87-88
inline JavaScript, 84
loops, 83-85
mixins, 87-89
Gmail, 190
Google Chrome, 7
variables, 82
includes, Jade, 87-88
JavaScript
indentation, 78-79
inheritance, 371-376
handling unpredictability, 37
inline JavaScript, 84
jsconf.eu, 7
input, 29-32
Heredocs, 371-372
installing
Heroku
deploying applications to,
174-175
preparing applications for,
173-174
hosting in the cloud, 169-171
HTML clients, creating, 68
CoffeeScript, 362-364
Express, 74
data
modules, 17
global installation, 22
local installation, 21-22
consuming, 270-274
sending, 268
Node.js debugger
STDIO, 136-140
Mocha, 163-166
lightweight frameworks, 73
third-party, 18
URL, 67
creating, 381
developing, 385-387
documentation, 22-23
websites, 381-383
MongoDB, 109-131
locating, 22-23
Events module, 317
CoffeeScript, 368-370
in Jade, 83-85
installing, 17
installing, 110-112
lovehateometer, creating,
252-262
global installation, 22
locating, 19-21
publicizing, 397
requiring, 17-18
messaging
Socket.IO, 189-191
exiting, 293
bi-directional data,
202-208
in Socket.IO, 202-208
data, broadcasting to
clients, 197-203
Middleware, 399-400
access control, 406-414
forcing users onto single
domain, 410-414
limiting access by IP
address, 407-409
439
N
network programming
frameworks, 54
networked I/O, unpredictability
of, 33-34
nibbles, 334
440
Nodester
Nodester, 180-183
Nodeunit, 156-157
parsing
prototype-based programming,
390-391
pushing
Twitter data to browser,
246-251
files
reading data from,
105-106
Q-R
ql.io, 37
OAuth, 241
object-oriented programming,
390-391
POST requests, 91
specifying, 94-95
pre-compilers, 364
preparing applications for Heroku,
173-174
printing stack traces, 140
redirects, 62
exiting, 293
processes, 291-293
communicating with,
308-310
killing, 308-309
signals, 293-295
programming
event-driven, 34
page structure
object-oriented, 390-391
organization, 96-97
prototype-based, 390-391
parameters, 94-96
Jade, 79-82
routing, 66, 91
in Express, 91
Twitter Bootstrap
specifying
441
dependencies, 23-24
GET requests, 92-93
scripts
creating, 297
passing arguments to,
298-300
signals to processess,
295-297
sending
server-side JavaScript, 8
Twitter, 241-244
BDD, 159-167
shebangs, 297
Mocha, 163-166
lovehateometer, creating,
252-262
signals, 293-295
sending to processes,
295-297
signing up for Twitter, 238-241
streams
modules, 385-387
Sinatra, 74
piping, 353-354
Vows, 159-162
Socket.IO, 191
readable, 347-351
writable, 351
strings
third-party modules, 18
CoffeeScript, 370
structure
of Express, 75-77
of module folders, 384-385
broadcasting to clients,
197-203
subclassing (CoffeeScript),
373-375
synchronous code, 50-53
Twitter
data, extracting meaning from,
243-247
data, pushing to browser,
246-251
lovehateometer, creating,
252-262
442
Underscore
W-Z
Underscore, 382
unpredictability, handling, 37
unpredictability of networked I/O,
33-34
URL module, 67
UTF-8, 106
WebSockets, 190-191
writable streams, 351
piping data from readable
streams, 353-354
writing
data to buffers, 340
data to files, 104
V
V8, 7
validating input data, 130-131
variables, Jade, 82
verbs (HTTP), 91
verifying
Node.js installation, 9-10
npm installation, 16
view rendering, 97-98
views (Backbone.js), 425-429
views folder (Express), 77
Vows, 159-162