Crunching the Spotify Web API
Tags: webdev, spotify, javascript, tutorial
Published: 2023-05-23 23:12:37

The Spotify API is one of the most widely used APIs in the API World. Since music is a major part of our lives, this API serves as tool that provides an extension of the individual from our private space into any application where we can stream our favorite artists.

Depending on the permissions and access to which you have been granted by the Spotify developer team, you are allowed to grab and manipulate the data of any authorized user to suit the needs of your application.

For example, applications like Discord, Last.fm, [and many more]("https://www.reddit.com/r/spotify/comments/3hhcco/any_good_spotifybased_online_applications/cu7fn1h/") make use of the Spotify API to provide a largely personalized listening experience to their users. 

How do these companies access and manipulate the API to suit their needs you ask? The answer is simple.


# Send a request, get a response.

While it is important to note that your use case will determine what endpoints you will make use of, there are certain things that are common to web applications that make use of the Spotify Web API which you would need to familiarize yourself with. 

You would need to understand how to perform the common CRUD operations you can perform with the API, this can be done by using [Postman](https://www.postman.com/postman/workspace/postman-team-collections/collection/7853927-755021ea-e6c9-47fd-a2b7-4348ea69914b?action=share&creator=19953081) to take a detailed look at the endpoints shared by the Spotify Web API. 

To get started with the Spotify API you will need to log into the [spotify developer dashboard]("https://developer.spotify.com/dashboard/login") and create a new project.

After you click on create-new-app you will see a modal where you will be asked to input: the specifications of your project, host url, and other details.

![Project creation modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/df01v8oz9haju4m2hmwo.png)
 
When you hit save, your project would be created and should look like this. This is to let Spotify know the url making requests to it's server is recognized and matches the information you provided. Now we can proceed with crunching the API.
 
![your created project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udpaywso0dhhuuh8fb85.png)


# Authentication and Authorization


To access a user's data via the API's endpoints, we would first need to authenticate the user.

This process makes a request to the [spotify account url]("https://accounts.spotify.com/authorize") with the required parameters and sends a hash token to your window url as a response.

This token sent to your url will be used to authorize the user every time a request is made to the Spotify API. Yes. Every, single, time. 
The best part? It expires in 3600 milliseconds.

To successfully make the request you would need to provide your:
1. Client ID
2. Redirect URL (your website url or localhost url) 
3. The Spotify authorization url and 
4. The scope of your request

LOGIN.JS

```
 function handleLogin() {
    const clientId = "aa7a764r6d6sd63t186314717ds7715318c";
    const redirectUrl = "http://localhost:3000";
    const apiUrl = "https://accounts.spotify.com/authorize";
    const scope = [
      "user-read-email",
      "user-read-private",
      "user-modify-playback-state",
      "user-read-currently-playing",
      "user-read-playback-state",
      "user-read-recently-played",
      "user-read-playback-position",
      "user-top-read",
    ];

    window.location.href = `${apiUrl}?client_id=${clientId}&redirect_uri=${redirectUrl}&scope=${scope.join(
      " "
    )}&response_type=token&show_dialog=false`;

    localStorage.clear();
  }
// Notice i set the dialog=false. If you set it to true you will be redirected to the spotify login page. If not, you continue like a boss.
// Also notice i cleared the local storage after logging in the user. I would explain why in a bit.


```

### Hold your horses. 

After your user is logged in, you would notice a `hash-token` is sent to the window url. We do not need the entire hash, we only need a part of it (the token). So we would get the hash from the window url and perform an operation on it to get the token using regular expressions. When we get the token we would supply it to our global state so it can be accessed throughout the entire application.

For my application i used the useContext and useReducer hooks for global state management. So when I get the token, it is immediately dispatched to my global state to be accessed throughout the entire application. 

Since this article does not cover state management in react, [this article](https://dev.to/ciphertron/usereducer-hook-to-the-rescue-2j48) by a former colleague of mine should explain in detail what exactly the Use Reducer Hook is and how to use it in state management.

```

  const [{ token }, dispatch] = useStateProvider();
  useEffect(() => {
    if (localStorage.getItem("spotify-token") === null || undefined) {
      localStorage.clear();
      const hash = window.location.hash;
      const token = hash.substring(1).split("&")[0].split("=")[1];
      window.localStorage.setItem("spotify-token", token);
      dispatch({ type: reducerCases.SET_TOKEN, token });
      window.location.hash = "";
    }
    const route = window.location.pathname;
    if (
      route === "/library" ||
      route === "/" ||
      route === "/home" ||
      route === "/search"
    ) {
      const token = localStorage.getItem("spotify-token");
      dispatch({ type: reducerCases.SET_TOKEN, token });
    }
  }, [token, dispatch]);


```

## Local storage and Sesame squares

If you remember that I cleared the local storage earlier, you deserve a bottle of wine!

But why did I do this?

It is because i need to store my token in the local storage for me to be able to access it after i refresh the page. Once you refresh your page, the API sends a request with the token to get the user's data for the application. If the token is available in the application's state, your requests will be successful if not they will be unsuccessful and you will be logged out and sent back to square 1.

So I cleared the local storage to make way for the `spotify-token` key with the `token` value so i can access it when ever i refresh the page and dispatch it to the application state for use all over again.

Simple innit? Great!


# Data fetching and sample responses

As we mentioned earlier, you would need the Spotify access token each time you make a request to the API in order to get a response. This has to happen asynchronously, since you will want to make sure you have your response before every other item on the page is loaded. 


## Get user's public playlists

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94wsy3qrreko85jsypao.png)

To get all the user's total playlists, we would make use of the `Get Playlists Items` endpoint `"https://api.spotify.com/v1/me/playlists"` which appears on spotify developers platform without the /me as `https://api.spotify.com/v1/playlists`. This request would be sent with authorization and content type headers to ensure the connection is secure.  


PLAYLISTS.JS

```

export default function Playlists() {
  const [{ token, playlists }, dispatch] = useStateProvider();
  useEffect(() => {
    const getPlaylistData = async () => {
      const response = await axios.get(
        "https://api.spotify.com/v1/me/playlists",
        {
          headers: {
            Authorization: "Bearer " + `token`,
            "Content-Type": "application/json",
          },
        }
      );
      const { items } = response.data;
      const playlists = items.map(({ name, id, images }) => {
        images = images[0].url;
        return { name, id, images };
      });
      dispatch({ type: reducerCases.SET_PLAYLISTS, playlists });
    };
    getPlaylistData();
  }, [token, dispatch]);

}

```

Once you dispatch your playlists data to your application state, you would be able to access the data through-out your entire application. Here is the response you would get if you log the first two playlists data (from my account) to the console: 


```

0: 

id: "0RGvWGzBsi9XE200cmpRpE"
images : 
"https://mosaic.scdn.co/640/ab67616d0000b27306728f8480e37e0c4321b1f0ab67616d0000b273131635f182833dfee67ec2beab67616d0000b2738a96302eb81c56c50491b958ab67616d0000b273ec3de434caed2b0e969da43f"
name: "Party 💃🏼"
[[Prototype]] : Object

1 : 

id : "6o5RV6butrAw2Hl2CRkxlx"
images : "https://mosaic.scdn.co/640/ab67616d0000b2731e340d1480e7bb29a45e3bd7ab67616d0000b2734640a26eb27649006be29a94ab67616d0000b2734891d9b25d8919448388f3bbab67616d0000b273d1243ff8852e722747ead762"
name : "Spanish dance hits 💃🏼"

[[Prototype]] : Object


```

## Playlists Response

Since we deconstructed only the image, id, and title values from the return object, that is what we get from the API response. Otherwise we would get every value associated with the every playlist object. Which would look like this.

```

collaborative : false
description :  ""
external_urls :  { spotify : 'https://open.spotify.com/playlist/0RGvWGnHCSi9XE200cmpRpE'
}
href : "https://api.spotify.com/v1/playlists/0RGvWGzBsi9XE200cmpRpE"
id : "0RGvWGzBsi9XE0220cmpRpE"
images : 
(3) [{…}, {…}, {…}]
name : "Party 💃🏼"
owner : 
{
  display_name: 'Heleen Mas Opor Poel', 
  external_urls: {…}, 
  href: 'https://api.spotify.com/v1/users/21wga7eqgd237q2l227zl4eppyhi', 
  id: '21wg3ez7e4q2l227zl4eppyhi', 
  type: 'user', 
  …
}

primary_color : null
public : false
snapshot_id : "MzU5LDUxYmNjZaacbKJCAHCOHADASI0ZDY1ZDdlN2FkMzgyOWM1ZTk4YWU2Njc="
tracks : 
{. 
href: 'https://api.spotify.com/v1/playlists/afuuq3811ydb81y01/tracks', total: 314}
type : "playlist"
uri : "spotify:playlist:0RGvWGzBsi9XE200cmpRpE"


```

This is a simple example of how to make a request to and get a response directly from the Spotify API. If you liked this article please give it a like and subscribe to my YouTube Channel at... oh wait, there's no YouTube Channel.  


See you later!


![increases volume](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5vvn9t68k9c47wkouh28.png)