Using Cavalry’s Web API to create a live league table.

Chris Hardcastle
Cavalry Animation
Published in
9 min readMar 13, 2023

One of Cavalry‘s many superpowers is the ability to connect external data into a fully featured authoring platform for animation. Combining these two disciplines can lead to some interesting results and, since adding the JavaScript APIs in Cavalry 1.4, I’ve been brushing up on my JavaScript — more recently learning to interact with API endpoints on the web and feed the data into Cavalry to drive the creative.

This article is a step-by-step guide for getting started with Cavalry’s Web API using a simple football league table as an example.

A Cavalry Composition populated with data from the Sportmonks API.

I should start this article with a confession — despite having many talented developers on the team, I’m not one of them! I’m on a learning journey myself so I hope this helps anyone interested in using Cavalry to represent external data in interesting ways.

Set Up

For this example we’ll be using Cavalry’s Web API to query an API from sportmonks.com. Sportmonks have a free tier which can be used to follow along using API 3.0.

The following script can be written in Cavalry’s JavaScript Editor but I’ve been really enjoying using Stallion from Scenery (aka Remco Janssen) which allows you to script in Visual Studio Code and also includes TypeScript definitions offering autocomplete and documentation while you type. 👍

Writing the Script

We’re going to create a very basic UI for this with a button to trigger the data from the API so let’s start by giving the script UI a title:

// Set the window title
ui.setTitle("Sportmonks API");

Next, let’s create a button:

// Create the button
const updateButton = new ui.Button('Refresh');

In order to access the Sportmonks API, you’ll need a token. This can be generated within your account. Once that’s generated, copy it and save it to a variable called apikey for use later on. To receive data for a league table we’ll also need a Season ID. On the free tier, the Scottish Premiership ID is 21787 (for the 23/24 season) so let’s also save that to a variable:

// Set API key and seasonId
const apikey = 'YOUR_TOKEN';
const seasonId = '21787';

Next we need to create a callback function to run when the Refresh button is clicked:

updateButton.onClick = function () {

}

And then within that function, create a new web client and authenticate it:

updateButton.onClick = function () {

// Make a new WebClient
const client = new api.WebClient('https://api.sportmonks.com');
client.addHeader('Authorization', apikey);
}

Sportmonks offer two types of authentication. For this example we’re using the request header method. As you can see, that is using the apikey variable we created earlier.

At this point you should be in a position to send a Get request. For this we need to build a url in a valid format which, for a Standings request, looks like this:

/v3/football/standings/seasons/{ID}

This base url returns a limited subset of the data available. For our league table we also want the team names and to do that we need to include the participant field. That can be achieved by adding ?include=participant to the end of the url. The final Get request looks like this:

updateButton.onClick = function () {

// Make a new WebClient
const client = new api.WebClient('https://api.sportmonks.com');
client.addHeader('Authorization', apikey);

// Send the Get Request...
client.get('/v3/football/standings/seasons/'+seasonId+'?include=participant');
}

Next, let’s add some basic error checking to the function. When making a request, Sportmonks returns a response code. The HTTP response code for a successful request is 200 so lets use an if statement to check for that and return the error code to the Message Bar (console) if anything goes wrong.

updateButton.onClick = function () {

// Make a new WebClient
const client = new api.WebClient('https://api.sportmonks.com');
client.addHeader('Authorization', apikey);

// Send the Get Request...
client.get('/v3/football/standings/seasons/'+seasonId+'?include=participant');

// Check it succeeded.
if (client.status() == 200) {
// do something here
}
else {
console.log('Sportmonks returned error code: ' + client.status());
}
}

We’re now ready to parse the JSON data and save it to an object within the if statement:

updateButton.onClick = function () {

// Make a new WebClient
const client = new api.WebClient('https://api.sportmonks.com');
client.addHeader('Authorization', apikey);

// Send the Get Request...
client.get('/v3/football/standings/seasons/'+seasonId+'?include=participant');

// Check it succeeded.
if (client.status() == 200) {

// Parse the JSON to an object.
const obj = JSON.parse(client.body());
}
else {
console.log('Sportmonks returned error code: ' + client.status());
}
}

In order to check the data is coming through, let’s generate the UI so we have a button to click and then log the data returned to the console. Add this to the bottom of your script (outside the button’s callback):

// Add the button.
ui.add(updateButton);
// Show the UI window.
ui.show();

…and, as a temporary check, let’s send the data from the Get request to the console by adding this to the end of the if statement:

console.log(JSON.stringify(obj));

The script should now look like this:

// Set the window title
ui.setTitle("Sportmonks API");

// Create the UI elements
const updateButton = new ui.Button('Refresh');

// Set API key and standingsId
const apikey = 'YOUR_TOKEN';
let seasonId = '21787';

updateButton.onClick = function () {

// Make a new WebClient
const client = new api.WebClient('https://api.sportmonks.com');
client.addHeader('Authorization', apikey);

// Send the Get Request
client.get('/v3/football/standings/seasons/'+seasonId+'?include=participant');

if (client.status() == 200) {

// Parse the JSON to an object.
const obj = JSON.parse(client.body());

// Preview the data in the console.
console.log(JSON.stringify(obj));
}
else {
console.log('Sportmonks returned error code: ' + client.status());
}
};

// Create the UI layout.
ui.add(updateButton);
// Show the window
ui.show();

Click the Run Script button in the JavaScript Editor and then click the Refresh button in the UI that pops up. You should see lots of JSON printed to the Message Bar (console) at the bottom of the Cavalry UI. This indicates we have successfully authenticated and sent a valid request.

In order to preview the data in a more readable form you might want to use a service like JSONlint to ‘prettify’ the output. Below is a stripped back version of the JSON response Sportmonks returns. This is a useful step to better understand the structure of the data and how to then extract specific properties from it.

{
"data": [
{
"points": 39,
"participant": {
"name": "Celtic"
}
},
{
"points": 35,
"participant": {
"name": "Rangers"
}
}
]
}

The next step is to filter the data down to just the properties we’re interested in — in our case, the points and name properties. To do that, let’s save the response to a variable and then use the map() method to store the values from all the points properties to an array called pointsResponse.

if (client.status() == 200) {

// Parse the JSON to an object.
const obj = JSON.parse(client.body());

// Store the response.
const response = obj.data

// Store all the values from the 'points' property
const pointsResponse = response.map(a => a.points);

}

Running console.log(pointsResponse); should now return an array of values representing the total points scored for each team — [39, 35, 29…].

We can then access the name property within the participant object using participant.name:

if (client.status() == 200) {

// Parse the JSON to an object.
const obj = JSON.parse(client.body());

// Store the response.
const response = obj.data

// Store all the values from the 'points' property
const pointsResponse = response.map(a => a.points);

// Store all the values from the 'name' property
const nameResponse = response.map(a => a.participant.name);

}

namesResponse should return an array of all the team names — [Celtic,Rangers,Hearts…].

Now we have prepared the data, we need to create a Composition in Cavalry containing Layers to assign the values stored in the pointsResponse and nameResponse arrays to.

Create the Composition

In Cavalry:

  1. Create a new Scene (File > New Scene).
  2. Create 2 Text Shapes (name them Points and Team).
  3. Move them in Position X so they are apart from each other.
  4. With the Team Text Shape loaded into the Attribute Editor, right click the String attribute and choose Add Array > String Array.
  5. With the Points Text Shape loaded into the Attribute Editor, click the + button on the String attribute and choose String Generator.
  6. Set the Precision and Padding to 0.
  7. Right click on the String Generator’s Number attribute and choose Add Array > Value Array.
  8. Use the +Add button to add 11 more indices to both Arrays (for a total of 12).
  9. Group the two Text Shapes.
  10. Select the Group and click the Duplicator button in the Shelf.
  11. Set the Duplicator’s Distribution to Linear, Count to 12, Size to -800 and Direction to Vertical.

You should have something that looks like this:

The Composition with Layers ready to receive the data.

Passing the data to Layers in the Scene

Back to the script, the last step is to use the data in the pointsResponse and nameResponse arrays to populate the indices for each of the Arrays in the scene. To do this, we can use a forEach() method to set the value of each item in the array to an index of both the Value and String Arrays.

A forEach loop for both properties is added to the bottom of the if statement in the final script below:

// Set the window title
ui.setTitle("Sportmonks API");

// Create the button
const updateButton = new ui.Button('Refresh');

// Set API key and seasonId
const apikey = 'YOUR_TOKEN';
const seasonId = '21787';

updateButton.onClick = function () {

// Make a new WebClient
const client = new api.WebClient('https://api.sportmonks.com');
client.addHeader('Authorization', apikey);

// Send the Get Request...
client.get('/v3/football/standings/seasons/'+seasonId+'?include=participant');

// Check it succeeded.
if (client.status() == 200) {

// Parse the JSON to an object.
const obj = JSON.parse(client.body());

// Store the response.
const response = obj.data

// Store all the values from the 'points' property
const pointsResponse = response.map(a => a.points);

// Store all the values from the 'name' property
const nameResponse = response.map(a => a.participant.name);

// Set each index of a Value Array with the Points data.
pointsResponse.forEach((item, index) => {
api.set("valueArray#1", {["array."+index]: item});
});

// Set each index of the String Array with the Name data.
nameResponse.forEach((item, index) => {
api.set("stringArray#1", {["array."+index]: item});
});
}
else {
console.log('Sportmonks returned error code: ' + client.status());
}
}

// Add the button.
ui.add(updateButton);
// Show the UI window.
ui.show();

Hit Run Script again in the JavaScript Editor to reload the UI and then hit the Refresh button. This should now populate the Arrays with the data returned from the API and be reflected in the Viewport!

From here, you can animate the Text within the Group and then add a Stagger to the Duplicator’s Shape Time Offset to create something similar to the example at the top of this article.

Now, each time the league changes, the Composition can be updated with one click of a button.

There are all sorts of APIs available for a variety of different fields including sports, events, weather, music, finance, social media… or maybe you have an internal API and are looking for ways to represent its data.

Sticking with the football theme, here’s a novel way to represent a team’s performance from graphic design graduate Noni.

A set up like this could be driven by API data and then exported from Cavalry on a weekly (or more regular) basis.

Hopefully this article gets you started integrating API data into Cavalry. If you have a project you’d like to explore or any questions then please get in touch via our support channels.

We’d love to see your creations so please share them with the #cavarlyapp hashtag so we don’t miss them. 😃

Cavalry is free forever to use or go Pro and unlock a world of creative possibilities. A Professional subscription to Cavalry is available from £16/month (paid annually) — sign up here.

--

--