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:
Socket.io is a technology that connects a client to a server using websockets. 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.
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. Navigate to the folder you want your project in, create a new folder for the 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:
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:
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:
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.
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.
Check the web browser console and you should see the following JSON data logged:
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.
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
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.
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.
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:
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, 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:
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
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.
First, I will need to create a div with an id of
Then, I will create the template. Here is the full script for the template (you will need to put this in the primary HTML script):
That is a lot! Lets go through this step by step. First, we import Preact, HTM, and something called Preact Signals. We will talk more about that later.
Next, we have some helper functions, which we will use later in the actual template. After that, we have the template component. In the first bit we iterate through all of the games and return markup for each game.
The first part of the markup shows the teams. Then, we get into the main part of the game data.
In the next section, we first check if the game has started yet. If not, we show when the game will start. If it has, we show the current score, as well as the current period and time left. This is where the helper functions are used.
Finally, if the game has ended, we just show the final score. The final line of the script is just to render the template in the div we created earlier.
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. If you want, you can create your own CSS styles.
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.
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!