6. The Spotify REST API
10m

Overview

It's time to jump into the we'll be using throughout this course.

In this lesson, we will:

  • Explore the Spotify REST API
  • Create a class that can manage our requests to different REST endpoints

Exploring real data

The data that our retrieve can come from all kinds of places: a database, a third-party API, webhooks, and so on. These are called . The beauty of is that you can mix any number of data sources to create an API that serves the needs of your client applications and graph consumers.

For the rest of the course, we're going to be using a lite, pared down version of the Spotify Web API. We can access the API documentation here.

https://spotify-demo-api-fe224840a08c.herokuapp.com/v1/docs/

A screenshot of the documentation for the Spotify REST API

How is our data source structured?

The next question we need to answer is how our data is structured in our REST API. This impacts how we retrieve and transform that data to match the in our schema.

Our goal is to retrieve data for featured playlists, and there's an endpoint for exactly that: GET /browse/featured-playlists. Click Try it out, then Execute to inspect the shape of the response we get back.

https://spotify-demo-api-fe224840a08c.herokuapp.com/v1/docs/

A screenshot of the featured playlist endpoint response

This response is lengthy! You'll notice a "playlists" key, which holds an array of playlist "items", which is a good start. Let's see in greater detail what matches, referring back to the Playlist type in our :

The response from /browse/featured-playlists
{
"message": "Featured playlists",
"playlists": {
"items": [
{
"collaborative": false,
"id": "6Fl8d6KF0O4V5kFdbzalfW",
"description": "Tooth-achingly sweet beats for your sweet eats",
"name": "Sweet Beats & Eats"
// ... other properties
},
{
"collaborative": false,
"id": "20RU4pHDte01QywpOL6ifh",
"description": "Set the barbecue mood. Upbeat and laid-back tracks complement the sizzle of the grill, turning your outdoor cooking sessions into a flavorful experience. For those who savor good music and great food, it's the perfect playlist",
"name": "Grilling Tunes"
// ... other properties
}
// other playlist objects
]
}
}

Here are the we need from our schema.

schema.graphql
type Playlist {
id: ID!
name: String!
description: String
}

Each object in the "items" array includes all of these properties, along with a bunch of properties that we don't need for now—images and followers, to name a few!

Setting up our data source

We know where our data is, and we understand how it's structured. Awesome. Now, we need a way to request everything it has to offer!

Because it's a very common task to fetch data from REST when building a API, provides a DataSource class for just that: the RESTDataSource.

Let's add this RESTDataSource class to our project.

In the terminal, in the root of our project, run:

npm install @apollo/datasource-rest

Now, we should start by creating a file that can hold all of the logic specific to this Spotify service—we'll call it spotify-api.ts, and we'll store it in a new folder called datasources.

📂 src
┣ 📂 datasources
┃ ┣ 📄 spotify-api.ts
┣ 📄 graphql.d.ts
┣ 📄 index.ts
┗ 📄 schema.graphql

First, we import the RESTDataSource class from the @apollo/datasource-rest package.

spotify-api.ts
import { RESTDataSource } from "@apollo/datasource-rest";

We'll declare a class called SpotifyAPI that extends RESTDataSource. While we're here, let's export it before we forget!

spotify-api.ts
export class SpotifyAPI extends RESTDataSource {
// ...
}

Next, let's assign our REST API's baseURL. This property is used as the prefix to all the calls.

spotify-api.ts
export class SpotifyAPI extends RESTDataSource {
baseURL = "https://spotify-demo-api-fe224840a08c.herokuapp.com/v1/";
}

Note: Be sure that your SpotifyAPI class' baseURL value ends with a /. This will allow our helper class to make requests and append new paths to the baseURL without any errors.

Data source methods

We need to give our class a method that can reach out to the REST API endpoint that returns playlist data. Let's call it getFeaturedPlaylists.

spotify-api.ts
getFeaturedPlaylists() {
// TODO
}

The RESTDataSource class provides helper methods for HTTP requests. In our case, we want to perform a GET request to the browse/featured-playlists endpoint.

spotify-api.ts
getFeaturedPlaylists() {
this.get("browse/featured-playlists");
}

The this.get method is a generic function that lets us pass it a hand-crafted return type. From exploring our JSON response, we know that we get back an object with a playlists key, which contains an array of items. We'll define the return type of items as an array of any types for now, but we'll improve on this later.

spotify-api.ts
getFeaturedPlaylists() {
this.get<{ playlists: { items: any[] }}>("browse/featured-playlists");
}

Let's create a new constant to hold the response, called response, and then return the data on response.playlists.items.

spotify-api.ts
getFeaturedPlaylists() {
const response = this.get<{ playlists: { items: any[] }}>("browse/featured-playlists");
return response?.playlists?.items ?? [];
}

Here, we're using optional chaining (?.) and the nullish coalescing operator (??) to validate in-line that each level of our response object exists, and return an empty array [] if not.

Finally, because this.get returns a promise, we need to await the results and make our entire getFeaturedPlaylists method async.

spotify-api.ts
async getFeaturedPlaylists() {
const response = await this.get<{ playlists: { items: any[] }}>("browse/featured-playlists");
return response?.playlists?.items ?? [];
}

Fantastic! Our file is complete for now.

Practice

Which of these are true about data sources?

Key takeaways

  • Bringing a new into our API starts with assessing the shape of its responses, and determining how best to map them to our schema .
  • We can extend the RESTDataSource class to introduce a REST API as a to our .

Up next

Our is ready to use! But how do we actually use the SpotifyClient class in our ?

In the next lesson, we'll explore functions, and see just how we can populate data for in our .

Previous

Share your questions and comments about this lesson

This course is currently in

beta
. Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.