hockey

How to Make a Real-Time Sports Application Using Node.js

Final product image
What You’ll Be Creating

In today’s article
I’m going to demonstrate how to make a web application that will display live
game scores from the NHL. The scores will update automatically as the games
progress.

This is a very
exciting article for me, as it allows me the chance to bring two of my favorite
passions together: development and sports.

The technologies
that will be used to create the application are:

  1. Node.js
  2. Socket.io
  3. MySportsFeed.com

If you don’t have
Node.js installed, visit their download
page now and set it up before continuing.

What Is Socket.io?

Socket.io is a
technology that connects a client to a server. In this example, the client is a
web browser and the server is the Node.js application. The server can have
multiple clients connected to it at any given time.

Once the connection
has been established, the server can send messages to all of the clients or an
individual client. In return, the client can send a message to the server, allowing for bi-directional real-time communication.

Before Socket.io,
web applications would commonly use AJAX, and both the client and server would
poll each other looking for events. For example, every 10 seconds an AJAX call
would occur to see if there were any messages to handle.

Polling for messages
caused a significant amount of overhead on both the client and server as it
would be constantly looking for messages when there were none.

With Socket.io, messages are received instantaneously, without needing to look for messages, reducing the overhead.

Sample
Socket.io Application

Before we consume
the real-time sports data, let’s create an example application to demonstrate
how Socket.io works.

To begin, I am going
to create a new Node.js application. In a console window, I am going to
navigate to C:GitHubNodeJS, create a new folder for my application, and
create a new application:

I used all the
default settings.

Because we are
making a web application, I’m going use an NPM package called Express to
simplify the setup. In a command prompt, install it as follows: npm install express
--save

And of course we
will need to install the Socket.io package: npm install
socket.io --save

Let’s begin by
creating the web server. Create a new file called index.js and place the
following code within it to create the web server using Express:

If you are not
familiar with Express, the above code example includes the Express library and
creates a new HTTP server. In this example, the HTTP server is listening on
port 3000, e.g. http://localhost:3000. A
route is created at the root of the site “/”. The result of the route
returns an HTML file: index.html.

Before we create the
index.html file, let’s finish the server by setting up Socket.io. Append the
following to your index.js file to create the Socket server:

Similar to Express,
the code begins by importing the Socket.io library. This is stored in a
variable called io. Next, using the io variable, an event handler is created with
the on function. The event being
listened for is connection. This event
is called each time a client connects to the server.

Let’s now create our
very basic client. Create a new file called index.html and place the following
code within:

The HTML above loads
the Socket.io client JavaScript and initializes a connection to the server. To
see the example, start your Node application: node index.js

Then, in your browser, navigate to http://localhost:3000. Nothing
will appear on the page; however, if you look at the console where the Node
application is running, two messages are logged:

  1. HTTP server started on port
    3000
  2. Client connection received

Now that we have a
successful socket connection, let’s put it to use. Let’s begin by sending a
message from the server to the client. Then, when the client receives the
message, it can send a response back to the server.

Let’s look at the
abbreviated index.js file:

The previous io.on function has been updated to include a
few new lines of code. The first, socket.emit, sends the message to the client. The sendToClient
is the name of the event. By naming events, you can send different types of
messages so the client can interpret them differently. The second addition is
the socket.on, which also contains an
event name: receivedFromClient. This
creates a function that accepts data from the client. In this case, the data is
logged to the console window.

That completes the
server-side amendments; it can now send and receive data from any connected
clients.

Let’s complete this
example by updating the client to receive the sendToClient
event. When it receives the event, it can respond with the receivedFromClient event back to the server.

This is accomplished
in the JavaScript portion of the HTML, so in the index.html
file, I have updated the JavaScript as follows:

Using the
instantiated socket variable, we have
very similar logic on the server with a socket.on
function. For the client, it is listening to the sendToClient
event. As soon as the client is connected, the server sends this message. When
the client receives it, it is logged to the console in the browser. The client
then uses the same socket.emit that the
server used to send the original event. In this instance, the client sends back
the receivedFromClient event to the
server. When the server receives the message, it is logged to the console
window.

Try it out for
yourself. First, in a console, run your Node application: node index.js. Then load http://localhost:3000 in your browser.

Check the web
browser console and you should see the following JSON data logged: {hello:
"world"}

Then, in the command
prompt where the Node application is running, you should see the following:

Both the client and
server can use the JSON data received to perform specific tasks. We will learn
more about that once we connect to the real-time sports data.

Sports
Data

Now that we have
mastered how to send and receive data to and from the client and server, this
can be leveraged to provide real-time updates. I chose to use sports data,
although the same theory is not limited to sports. Before I began this project,
I researched different sports data. The one I settled on, because they offer
free developer accounts, was MySportsFeeds (I am not affiliated with them in any way). To access the real-time
data, I signed up for an account and then made a small donation. Donations start at
$1 to have data updated every 10 minutes. This will be good for the example.

Once your account is
set up, you can proceed to setting up access to their API. To assist with this,
I am going to use their NPM package: npm install
mysportsfeeds-node --save

After the package
has been installed, API calls can be made as follows:

In the example
above, be sure to replace the call to the authenticate
function with your username and password.

The following code
executes an API call to the get the NHL scoreboard for today. The fordate variable is what specifies today. I’ve
also set force to true so that a response is always returned, even when the data has not changed.

With the current
setup, the results of the API call get written to a text file. In the final
example, this will be changed; however, for demonstration purposes, the results
file can be reviewed in a text editor to understand the contents of the
response. The results contain a scoreboard
object. This object contains an array called gameScore.
This object stores the result of each game. Each object contains a child object
called game. This object provides the
information about who is playing.

Outside of the game
object, there are a handful of variables that provide the current state of the
game. The data changes based on the state of the game. For example, when the
game hasn’t started, there are only a few variables that tell us the game is not
in progress and has not started.

When the game is in
progress, additional data is provided about the score, what period the game is
in, and how much time is remaining. We will see this in action when we get to
the HTML to show the game in the next section.

Real-Time Updates

We have all the
pieces to the puzzle, so it is now time to put the puzzle together to reveal the
final picture. Currently, MySportsFeeds has limited support for pushing data to
us, so we will have to poll the data from them. Luckily, we know the data only
changes once every 10 minutes, so we don’t need to add overhead by polling for
changes too frequently. Once we poll the data from them, we can push those
updates from the server to all clients connected.

To perform the
polling, I will use the JavaScript setInterval
function to call the API (in my case) every 10 minutes to look for updates.
When the data is received, an event is sent to all of the connected clients.
When the clients receive the event, the game scores will be updated with
JavaScript in the web browser.

MySportsFeeds will
also be called when the Node application first starts up. This data will be
used for any clients who connect before the first 10-minute interval. This is
stored in a global variable. This same global variable is updated as part of
the interval polling. This will ensure that when any new clients connect after
the polling, they will have the latest data.

To assist with some
code cleanliness in the main index.js
file, I have created a new file called data.js.
This file will contain a function that is exported (available in the index.js file) that performs the previous call
to the MySportsFeeds API. Here are the full contents of that file:

A getData function is exported and returns the
result of the call, which in this case is a Promise
that will be resolved in the main application.

Now let’s look at
the final contents of the index.js file:

The first seven lines of
code above instantiate the required libraries and the global latestData variable. The final list of
libraries used are: Express, Http Server created with Express, Socket.io, and
the aforementioned data.js file just
created.

With the necessities
taken care of, the application populates the latestData
for clients who will connect when the server is first started:

The next few lines
set up a route for the root page of the website (http://localhost:3000/) and start the HTTP
server to listen on port 3000.

Next, the Socket.io
is set up to look for connections. When a new connection is received, the server
emits an event called data with the
contents of the latestData variable.

And finally, the
final chunk of code creates the polling interval. When the interval occurs, the
latestData variable is updated with the
results of the API call. This data then emits the same data event to all clients.

You may notice that
when the client connects and an event is emitted, it is emitting the event with
the socket variable. This approach will
send the event to that connected client only. Inside the interval, the global io is used to emit the event. This will send
the event to all clients.

That completes the
server. Let’s work on the client front-end. In an earlier example, I created a basic index.html file that
set up the client connection that would log events from the server and send one
back. I am going to extend that file to contain the completed example.

Because the server
is sending us a JSON object, I am going to use jQuery and leverage a jQuery
extension called JsRender.
This is a templating library. It will allow me to create a template with HTML
that will be used to display the contents of each NHL game in an easy-to-use, consistent manner. In a moment, you will see the power of this library. The
final code is over 40 lines of code, so I am going to break it down into
smaller chunks, and then display the full HTML together at the end.

This first part
creates the template that will be used to show the game data:

The template is
defined using a script tag. It contains
the id of the template and a special script type called text/x-jsrender. The
template defines a container div for
each game that contains a class game to
apply some basic styling. Inside this div, the templating begins.

In the next div, the
away and home team are displayed. This is done by concatenating the city and
team name together from the game object
from the MySportsFeed data.

{{:game.awayTeam.City}} is
how I define an object that will be replaced with a physical value when the
template is rendered. This syntax is defined by the JsRender library.

Once the teams are
displayed, the next chunk of code does some conditional logic. When the game is
unPlayed, a string will be outputted
that the game will start at {{:game.time}}.

When the game is not
completed, the current score is displayed: Current Score: {{:awayScore}} -
{{:homeScore}}
. And finally, some tricky little logic to identify what period
the hockey game is in or if it is in intermission.

If the variable currentIntermission is provided in the
results, then I use a function I defined called ordinal_suffix_of, which will convert the period number to read: 1st (2nd, 3rd, etc.)
Intermission.

When it is not in
intermission, I look for the currentPeriod
value. This also uses the ordinal_suffix_of  to show that the game is in the 1st (2nd, 3rd,
etc.) period.

Beneath this,
another function I defined called time_left
is used to convert the number of seconds remaining into the number of
minutes and seconds remaining in the period. For example: 10:12.

The final part of
the code displays the final score because we know the game has completed.

Here is an example
of what it looks like when there is a mix of finished games, in progress games,
and games that have not started yet (I’m not a very good designer, so it looks
as you would expect when a developer makes their own User Interface).

An example of finished games

Next up is a chunk
of JavaScript that creates the socket, the helper functions ordinal_suffix_of
and time_left, and a variable that references the jQuery template created.

The final piece of
code is the code to receive the socket event and render the template:

I have a placeholder
div with the id of data. The result of
the template rendering (tmpl.render) writes the HTML to this container. What is
really neat is that the JsRender library can accept an array of data, in this
case data.scoreboard.gameScore, that
iterates through each element in the array and creates one game per element.

Here is the final
HTML and JavaScript all together:

Start the Node
application and browse to http://localhost:3000
to see the results for yourself!

Every X minutes, the
server will send an event to the client. The client will redraw the game
elements with the updated data. So when you leave the site open and
periodically look at it, you will see the game data refresh when games are
currently in progress.

Conclusion

The final product
uses Socket.io to create a server that clients connect to. The server fetches
data and sends it to the client. When the client receives the data, it can
seamlessly update the display. This reduces load on the server because the
client only performs work when it receives an event from the server.

Sockets are not
limited to one direction; the client can also send messages to the server. When
the server receives the message, it can perform some processing.

Chat applications
would commonly work this way. The server would receive a message from the
client and then broadcast to all connected clients to show that someone has
sent a new message.

Hopefully you
enjoyed this article as I had a blast creating this real-time sports
application for one of my favorite sports!

Powered by WPeMatico

Leave a Comment

Scroll to Top