How To Create a Sports Website With Ruby (with the Sportpage Feeds API)

sports website created by ruby

In this article, we’d like to show how you can build a simple scoreboard for the major US leagues using Ruby and the Sportspage Feeds API. An initial approach to this would require sourcing the data from multiple APIs (or scraping), which would, in turn, require writing code for different response types and putting them all together. Luckily, using RapidAPI and the Sportspage Feeds API, we can save a lot of time and simply focus on what we want to build.

Related: How to use the NBA API (with Python)

What is the Sportspage Feeds API?

The Sportspage Feeds API provides a plethora of data for a large range of US leagues. From the NBA to NCAAF, you can get past and scheduled game data, including game odds.

Sportspage feed api output

You can get information on the teams, the venue, and of course and the score. If the game is ongoing, you can get partial scores. Moreover, you can get lists of conferences and divisions, plus detailed information about each team (you can even get the name of the mascot). The amount of data is really impressive and should allow you to build great integrations.

Connect to the Sportspage Feeds API

What we want to build

Our website will consist of a single page, which will show a list of sports leagues. The user will then be able to click any of the leagues and see a list of past and future games. Each game should show the names of the teams, the total scores for the game, plus the scores for each of the periods for each team.

sports website created by ruby

To simplify the designing of the website, we’ll be using Bootstrap. Bootstrap is a web design framework that greatly simplifies wireframing a project like this one and allows us to focus more on the core build.

What you’ll need

For you to follow along, you will need:

To install Ruby, we’d rather refer you to their official guides. Depending on your platform, the instructions can differ, so you should follow their instructions. The latest Ruby version will do just fine. After you’re all set up, you’ll need a RapidAPI account. Sign up on their website, then make sure you subscribe to the Sportspage Feeds API. They offer a free plan, which should be just enough for this tutorial. To do this, go to the Sportspage Feeds API page, click on the “Pricing” tab, then on the subscribe button on the “Basic” plan.

Connect to the Sportspage Feeds API

Building the website

We’ll go step by step, building the features as we go along. First, let’s make sure we have everything we need to set up. Create a new folder in your projects directory, and add a Gemfile. In there, add:

# Gemfile
source 'https://rubygems.org'

gem 'sinatra'
gem 'excon'

Run bundle install to install both dependencies. We’ll be using Sinatra to serve our website, while Excon will be the networking library we’ll use to fetch data from the Sportspage API. Next, create a file called app.rb and add this to it:

# app.rb
require 'sinatra'
require 'excon'

get '/' do
  erb :index
end

This is an extremely simple Sinatra app that serves a template file when the / path is requested. erb refers to Embedded Ruby, and it’s a way to embed Ruby in a different language, in this case, HTML. By default, Sinatra will look for a file called index.erb in a views folder. Go ahead and create that folder and file, and add this to it:

<!-- views/index.erb -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>SportsPage</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
  Hello world!
</body>
</html>

Nothing very exciting for now. Just a plain HTML document with an import for Bootstrap. If you run ruby app.rb. and point your browser to http://localhost:4567, you should read “Hello world!”.

Showing a list of leagues

Sportspage Feeds API supports the following major US leagues:

For our users to filter by them, let’s add links to our page. Replace the “Hello world!” string in the index.erb file with this:

<div class="container">
  <section>
    <h1 class="text-center">Scores</h1>
    
    <ul class="nav nav-pills nav-fill">
      <li class="nav-item">
        <a class="nav-link" href="/?league=NFL">NFL</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/?league=NBA">NBA</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/?league=MLB">MLB</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/?league=NHL">NHL</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/?league=NCAAF">NCAAF</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/?league=NCAAB">NCAAB</a>
      </li>
    </ul>
  </section>
</div>

This should render a nice horizontal list of links to each league. The links should point to the same page (notice the / path), so clicking them should simply reload the page. Notice that the URL has a parameter that specifies the league the user clicks, so we can grab that and fetch the right games.

Connect to the Sportspage Feeds API

Have an API you want to add to our API Marketplace?

#DIV_1 {
bottom: 0px;
box-sizing: border-box;
color: rgb(10, 10, 10);
cursor: pointer;
float: left;
height: 95px;
left: 0px;
position: relative;
right: 0px;
text-decoration: none solid rgb(10, 10, 10);
text-size-adjust: 100%;
top: 0px;
width: 270px;
column-rule-color: rgb(10, 10, 10);
perspective-origin: 135px 47.5px;
transform-origin: 135px 47.5px;
caret-color: rgb(10, 10, 10);
background: rgb(0, 140, 220) none repeat scroll 0% 0% / auto padding-box border-box;
border: 1px solid rgb(227, 224, 224);
border-radius: 0 0 4px 4px;
font: normal normal 400 normal 16px / 24px Lato, sans-serif;
margin: 0px 0px 15px;
outline: rgb(10, 10, 10) none 0px;
}/*#DIV_1*/

#A_2 {
box-sizing: border-box;
text-size-adjust: 100%;
perspective-origin: 0px 0px;
transform-origin: 0px 0px;
font: normal normal 400 normal 16px / 24px Lato, sans-serif;
}/*#A_2*/

#DIV_3 {
bottom: 0px;
box-sizing: border-box;
color: rgb(0, 0, 238);
cursor: pointer;
float: left;
height: 63px;
left: 0px;
position: relative;
right: 0px;
text-decoration: none solid rgb(0, 0, 238);
text-size-adjust: 100%;
top: 0px;
width: 70px;
column-rule-color: rgb(0, 0, 238);
perspective-origin: 35px 31.5px;
transform-origin: 35px 31.5px;
caret-color: rgb(0, 0, 238);
border: 0px none rgb(0, 0, 238);
border-radius: 5px 5px 5px 5px;
font: normal normal 400 normal 16px / 24px Lato, sans-serif;
margin: 15px 5px 15px 15px;
outline: rgb(0, 0, 238) none 0px;
}/*#DIV_3*/

#IMG_4 {
bottom: -35.0781px;
box-sizing: border-box;
color: rgb(0, 0, 238);
cursor: pointer;
display: block;
height: 66.5781px;
left: 35px;
max-width: 100%;
position: absolute;
right: -35px;
text-decoration: none solid rgb(0, 0, 238);
text-size-adjust: 100%;
top: 31.5px;
vertical-align: middle;
width: 70px;
column-rule-color: rgb(0, 0, 238);
perspective-origin: 35px 33.2813px;
transform: matrix(1, 0, 0, 1, -35, -33.5);
transform-origin: 35px 33.2813px;
caret-color: rgb(0, 0, 238);
border: 0px none rgb(0, 0, 238);
font: normal normal 400 normal 16px / 24px Lato, sans-serif;
outline: rgb(0, 0, 238) none 0px;
}/*#IMG_4*/

#DIV_5 {
box-sizing: border-box;
color: rgb(255, 255, 255);
cursor: pointer;
float: left;
height: 46px;
text-decoration: none solid rgb(255, 255, 255);
text-size-adjust: 100%;
width: 168px;
column-rule-color: rgb(255, 255, 255);
perspective-origin: 84px 23px;
transform-origin: 84px 23px;
caret-color: rgb(255, 255, 255);
border: 0px none rgb(255, 255, 255);
font: normal normal 400 normal 16px / 24px Lato, sans-serif;
margin: 22px 0px 0px 5px;
outline: rgb(255, 255, 255) none 0px;
}/*#DIV_5*/

#SPAN_6 {
box-sizing: border-box;
color: rgb(255, 255, 255);
cursor: pointer;
display: block;
float: left;
width: 150px;
height: 27px;
text-decoration: none solid rgb(255, 255, 255);
text-size-adjust: 100%;
width: 107.047px;
column-rule-color: rgb(255, 255, 255);
perspective-origin: 53.5156px 13.5px;
transform-origin: 53.5156px 13.5px;
caret-color: rgb(255, 255, 255);
border: 0px none rgb(255, 255, 255);
font: normal normal 700 normal 18px / 27px Lato, sans-serif;
outline: rgb(255, 255, 255) none 0px;
}/*#SPAN_6*/

#SPAN_7 {
box-sizing: border-box;
color: rgb(255, 255, 255);
cursor: pointer;
display: block;
float: left;
height: 19px;
text-decoration: none solid rgb(255, 255, 255);
text-size-adjust: 100%;
width: 110.188px;
column-rule-color: rgb(255, 255, 255);
perspective-origin: 55.0938px 9.5px;
transform-origin: 55.0938px 9.5px;
caret-color: rgb(255, 255, 255);
border: 0px none rgb(255, 255, 255);
font: normal normal 700 normal 13px / 19.5px Lato, sans-serif;
outline: rgb(255, 255, 255) none 0px;
}/*#SPAN_7*/

Fetching the games

The user can now click on a league, so let’s fetch and show the games and the scores. But before we do that, we need to grab our API key and host from the RapidAPI website. Go to the Sportspage Feed API page and grab it from the endpoints tester at the bottom, like the screenshot shows:

sportspage feed api key

Note them down as you’ll need them for the next snippet. Let’s add a method in our app.rb file to fetch the available games, depending on the selected league:

def fetch_games(league)
  url = "https://sportspage-feeds.p.rapidapi.com/games?league=#{league}"

  response = Excon.get(
    url,
    headers: {
      'X-RapidAPI-Host' => 'HOST',
      'X-RapidAPI-Key' => 'API_KEY'
    }
  )

  JSON.parse(response.body)['results']
end

This method creates a URL to fetch games and appends the passed league as a query string parameter. Then, it fetches the games using Excon, and parses the result as JSON. If you check the sample response for the games endpoint, you’ll notice the results come in the results attribute, so let’s just return that instead of the whole response object. Remember to replace the HOST and API_KEY in the code! Now, modify the get method like so:

get '/' do
  league = params['league']

  games = league ? fetch_games(league) : []

  erb :index, locals: { league: league, games: games }
end

Here, we get the selected league from the URL’s query string, by using the params hash. If it’s defined, we call the fetch_games method to fetch that league’s games, otherwise, we just default to an empty array. After that, we render the same template, but this time we pass some “locals”, which are variables we can use in the template itself. The locals we need to pass are  league and games. After this, we can modify the index.erb template a bit, by adding this:

<% if games.any? %>
  <section>
    <% games.each do |game| %>
      <div class="card mb-3">
        <div class="card-body">
          <div class="row text-center">
            <!-- Home Team Name and Score -->
            <div class="col-sm-5">
              <h4><%= game['scoreboard']['score']['home'] %></h4>
              <p><%= game['teams']['home']['team'] %></p>
            </div>

            <!-- Dash separator -->
            <div class="col-sm-2">
              <h4>&mdash;</h4>
            </div>

            <!-- Away Team Name and Score -->
            <div class="col-sm-5">
              <h4><%= game['scoreboard']['score']['away'] %></h4>
              <p><%= game['teams']['away']['team'] %></p>
            </div>
          </div>

          <!-- add scores here -->
        </div>
      </div>
    <% end %>
  </section>
<% else %>
  <section>
    <p class="text-center">No games found</p>
  </section>
<% end %>

Quite a bit going on here, but it’s mostly Bootstrap boilerplate. We’re building a scoreboard to show the home and away teams’ names and scores. Each “card” consists of three columns, one for the home team’s name and score, a second column for a dash to separate the scores, and a third for the away team’s name and score. In case the games array is empty, we’ll show an empty message. If you restart the Sinatra server and refresh your browser, you should see something similar to this, depending on what league you click (and what time of the year it is):

sportspage feed website example 1

Connect to the Sportspage Feeds API

Adding more data

If you check out the response you get from the API (you can do this in the RapidAPI dashboard, by pressing the “Test Endpoint” button) you’ll notice there’s a lot of data for each game. Let’s use that and add some of it to our site. We’ll build a table that shows each team’s score son each period. To do this, replace the <!-- add scores here --> comment with this:

<div class="row">
  <div class="col-sm-12">
    <table class="table">
      <thead>
        <tr>
          <th>Team</th>
          <% game['scoreboard']['score']['awayPeriods'].count.times do |i| %>
            <th><%= i + 1 %></th>
          <% end %>
          <th>Total</th>
        </tr>
      </thead>

      <tbody>
        <tr>
          <th><%= game['teams']['home']['team'] %></th>
          <% game['scoreboard']['score']['homePeriods'].each do |period| %>
            <td><%= period %></td>
          <% end %>
          <td><%= game['scoreboard']['score']['home'] %></td>
        </tr>

        <tr>
          <th><%= game['teams']['away']['team'] %></th>
          <% game['scoreboard']['score']['awayPeriods'].each do |period| %>
            <td><%= period %></td>
          <% end %>
          <td><%= game['scoreboard']['score']['away'] %></td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

Again, this is mostly Bootstrap and HTML boilerplate to create a table. In the header of the table, we need to make sure we create enough columns to show all periods. We can do this by using the times method (which yields a block a certain amount of times, in this case, the number of periods in a game) on any of the arrays that contain the scores for either the home or away team. Then, in the body, we do something similar to display the actual scores, plus the total. Restarting the Sinatra server and refreshing should give you something like this:

sportspage feed website example 2

Connect to the Sportspage Feeds API

Conclusion

We hope this quick introduction to the Sportspage Feed API gave you an idea of what you can build with it. As an exercise, make sure the code works well when a game has not been played yet (ie. there are no scores), and also when a game is live. There’s even an attribute in the response called periodTimeRemaining which you can use to display the time remaining in the game.

5
/
5
(
1

vote

)

The post How To Create a Sports Website With Ruby (with the Sportpage Feeds API) appeared first on Last Call – The RapidAPI Blog.

Source: RapidAPI

Leave a Reply

Your email address will not be published.


*