Websockets with Socket.io
Objectives
Describe what realtime means, and how channels & open sockets push data to clients
Set up websockets on the server side
Use jQuery to update the client side
Getting Started
NOTE: There are two options for this lesson
Access the starter code for the codealong here: https://github.com/WDI-SEA/socket-io-starter
Follow the Socket.io chat example, which illustrates sending and receiving messages on both the client and server: http://socket.io/get-started/chat/
Web basics recap
Let's take it back and talk about how the web works. In very simple terms: you have a client - a program that can make requests to the web - and a server - a computer somewhere that holds information/code. When you want some information, your browser sends a request to get some data and then the server responds. This can be with a GET request or an AJAX request, but in essence, the client is always saying "give me some data".
What are the issues with this?
Well, the client is in 'control' - the server might have updates, but the client doesn't know about them - and the client has to request information it may not be familiar with.
Alas! In comes polling! The client can keep 'polling' the server to see if it has any more data.
What are the issues with polling?
It's slow! Polling every n
seconds isn't ideal, and if you poll too often, your bandwidth will go through the roof and slow your application down.
Enter Websockets
WebSockets solves all this. It maintains an open connection from Server <-> Client that we can use to 'push' information and get information, constantly, like push notifications on your phone (Gmail through Mail.app example).
Unlike HTTP requests, once a connection is established with websockets, you don't get continuous meta data like types, user-agents, cookies, dates, etc.
Installing WebSockets
We're going to add functionality to our application that will pull a constant stream of tweets from Twitter's API. First thing we need is to install the socket.io package. Jump into the starter code folder and:
Then, require it in our app with a few changes. First let's add a new require for the http module which gives us the server that socket.io needs to listen to. In index.js
What's the difference between app & require('http')
This second way - creating an HTTP server yourself instead of having Express create one for you - is useful if you want to reuse the HTTP server, for example to run socket.io within the same HTTP server instance:
We need change at the bottom from app
to server
:
Also, add to index.js
below the http
variable:
Add Twitter Streaming API
Great! We're also going to using another module called twit to use with the Twitter Streaming API.
And add to your index.js
at the top:
Setting up our Twitter app
To make any of our apps work with Twitter, we need to declare our app as a Twitter application using apps.twitter.com.
Let's go to Twitter and create a new 'app':
Name: express-twitter-stream (you'll have to change this to something unique)
Description: Small app to stream tweets from Twitter.
Website: http://127.0.0.1
Then, navigate to Keys and Access Tokens, generate My Access Token, and copy the keys into a .env
file like so:
Instantiate new Twitter
In JS, we can access environment variables using the following syntax:
Create new Twit client in index.js
:
You can console log this to see if it has worked. Don't forget to run foreman
!:
Get Tweets with a websocket
Now we set up our websocket on the server-side. There are a number of reserved words - connect, connection, message, disconnect - that can't be used elsewhere. We want our tweets to stream when we connect to the page so we open a connect channel.
Inside, we set up our tweet socket and finally we emit our tweet on the tweets channel.
Note that socket refers to an individual connection, while io refers to all socket connections. Keep this in mind when emitting data.
Client Side
Now that's the server side sorted, now let's do the client. Open up our layout.ejs
and add a few things - jQuery, our socket.io library and an empty JS file:
Notice that the path is relative - that's being done for you by Node.
Let's check in Chrome's console
Open up Chrome's console using cmd+alt+j
Then in script.js
, add in our receiving code:
Notice there's no URL provided to io(), since it defaults to trying to connect to the host that serves the page.
We use one of the reserved events ('connect') to log out the fact we are connected, and then, we hook up to the tweets channel and start logging out what is received.
This is great! We now have own tweets streaming but only to the console. Let's get it on the page with some jQuery.
Back to the server-side
Go back to our index.js
and tidy up the tweet data we're sending through:
Note the change to: socket.emit('tweets', data);
Let's change the views
Add a container in index.ejs
:
Render the tweets with jQuery and amend script.js
:
The Twitter stream should now be working. Try opening up another browser window and see all the browser windows update in real time.
Additional Resources
Great example of two-way event emission
How Facebook and Gmail implement real time notifications
Note that websockets are a HTML5 spec, and there must be fallbacks (like long polling) for browsers that don't support websockets.
Last updated