Using spotify-web-sdk to handle requests to the Spotify Web API
Tags: react, webdev, opensource, showdev
Published: 2019-04-29 18:00:15

---
title: Using spotify-web-sdk to handle requests to the Spotify Web API
published: true
description: This is how we used spotify-web-sdk to fastly build an application.
tags: react, webdev, opensource, showdev
series: Meet spotify-web-sdk!
cover_image: https://thepracticaldev.s3.amazonaws.com/i/6a3wfu20y6db2gojyuzi.png
---

This is the first post of the **Meet spotify-web-sdk!** series, in which we ([Call Us What You Want](https://dev.to/calluswhatyouwant/call-us-what-you-want-is-officially-on-board-1km)) will comment about the possibilities offered by the Spotify Web API and some of our code design choices. In this first part, we'll see how spotify-web-sdk can help build [an application](https://github.com/calluswhatyouwant/spotify-playlist-editor) that uses Spotify Web API to retrieve information and manage a user's data.

{% github https://github.com/calluswhatyouwant/spotify-web-sdk %}

# The real-world problem (*Another day, another drama*)

The Album section of my Spotify library is very cluttered — the thing is, if I save a new single, it ends up being saved as an album as well. Maintaining a simple way to access each album is important to me because most of the time I'd rather listen to a whole EP/LP from start to finish instead of hitting the shuffle button in a playlist.

![Spotify Albums screenshot](https://thepracticaldev.s3.amazonaws.com/i/pqktrt0hmqdhrxudc6ta.png)
<figcaption><b>ME!</b> and <b>The Other Side</b> are both singles but also show up in my Spotify library as albums.</figcaption>

I came up with a seemingly simple solution: I created [a playlist](https://open.spotify.com/user/jrobsonjr/playlist/7lWSJamQptWauCMIEDXgYC?si=HZZTKAY8RWObSGEdYm-4uA) containing the first track of each album I've listened to. Having this playlist is also a great way to keep track of the day I first listened to new releases (at least when I remember to add them right away). Problem solved... at least partially. Well, to keep things tidier, I still wanted to sort my album references by their release date. The problem is that Spotify doesn't support this sorting method, even though users have been requesting it for [over five years](https://community.spotify.com/t5/Live-Ideas/Your-Music-Sort-Music-in-quot-Your-Music-quot-by-Year/idi-p/744893). Guess we can't have it all.

I searched for tools that managed this sorting for me and there's a great web app named [Sort Your Music](http://sortyourmusic.playlistmachinery.com/). Even though it's pretty simple and efficient to use, their sorting approach overwrites the addition dates of tracks. I know I'm being quite a handful ([uh](https://genius.com/Taylor-swift-me-lyrics)), but knowing it's possible, I decided to implement my own tool. Nothing like a little DIY, right?

# I'm alright with a slow burn

Managing playlists with the Spotify Web API can be done using two endpoints: [one that allows replacing all tracks](https://developer.spotify.com/documentation/web-api/reference/playlists/replace-playlists-tracks) and [another one that can be used to reorder a track or a block of tracks](https://developer.spotify.com/documentation/web-api/reference/playlists/reorder-playlists-tracks/). Unlike the first one, the latter doesn't touch the timestamp that indicates when the tracks were added and the identifier of who added them (for collaborative playlists).

![Visualization of track reordering](https://thepracticaldev.s3.amazonaws.com/i/lfcnbuvlnmvemungeuyu.png)
<figcaption>Visualization of how the "reorder a playlist's tracks" endpoint works. Source: <a href="https://developer.spotify.com/documentation/web-api/reference/playlists/reorder-playlists-tracks/">Spotify for Developers</a></figcaption>

As seen above, the endpoint works in such a way that sorting a playlist requires a lot of consecutive requests (basically, one request per track in the playlist), which also means it can take much longer than simply overwriting everything. Sacrifices had to be done, but the result is exactly what expected: here's [Spotify Playlist Editor](https://github.com/calluswhatyouwant/spotify-playlist-editor)!

![Spotify Playlist Editor](https://thepracticaldev.s3.amazonaws.com/i/7ookuks66s0203i3s9n3.png)
<figcaption>Once logged in, something like that should appear to you.</figcaption>

# Detailing the process (but not too much)

I wanted to prototype a React application as fast as I could, so I used [create-react-app](https://facebook.github.io/create-react-app/), saving me a lot of time of configuration. In general, I suggest everyone to take their time to understand how to create a React app from scratch, but this sure comes in handy! To keep things simple, **Spotify Playlist Editor** is serverless but still lets anyone access their Spotify data by implementing the [Implicit Grant Flow](https://developer.spotify.com/documentation/general/guides/authorization-guide/).

I included some packages and toolkits to simplify the coding process (for instance, [Bootstrap](https://getbootstrap.com) so that I could worry less about styles and [prettier](https://prettier.io/) to help keep the code neat). I think it's worth mentioning I'm using [Flow](https://flow.org) for static type checking. I like that JavaScript is a dynamically typed language, but since the SDK deals with a lot of models which have each many attributes, Flow becomes a great ally.

![IntelliSense](https://thepracticaldev.s3.amazonaws.com/i/jjhcgbimvjazm6wcvcb8.png)
<figcaption>Also, React + Flow + <a href="https://code.visualstudio.com/docs/editor/intellisense">IntelliSense</a> is a dream combo.</figcaption>

## Meet Spotify Web API's self-proclaimed best friend, spotify-web-sdk!

Here's a snippet of code taken from the *UserPage* component. You can see some imports made directly to the SDK:

```javascript
/* @flow */

import React, { Component } from 'react';
import {
    /* Functions that wrap Spotify endpoints */
    init,
    getCurrentUserPlaylists,
    getCurrentUserProfile,
    /* Models */
    Page,
    PlaylistSimplified,
    PrivateUser,
} from 'spotify-web-sdk';

type Props = {
    history: any,
};

type State = {
    page: Page<PlaylistSimplified>,
    playlists: PlaylistSimplified[],
    user: PrivateUser,
};

class UserPage extends Component<Props, State> {
    // ...
}
```

Once the user has connected to Spotify, *UserPage* is the main page of the application. Its main purpose is to display a list of the current user's playlists, with a button to allow them to select a playlist of interest. Initially, five playlists are retrieved:

```javascript
componentDidMount = async () => {
    const page = await getCurrentUserPlaylists({ limit: 5 });
    this.setState({
        page,
        playlists: page.items,
    });
}
```

By keeping the page object in the state, requesting more playlists is as simple as it gets. This is because the following logic is already implemented on spotify-web-sdk's Page object: 

```javascript
class Page<T> {
    // ...
    async getNextPage() {
        if (!this.hasNext()) throw new Error('There are no more pages');
        const params = {
            ...this.queryParams,
            limit: this.limit,
            offset: this.offset + this.limit,
        };
        const response = await this.getAxiosPageInstance().get('/', { params });
            return new Page<T>(response.data, this.t, this.wrapper);
    }
}
```

Therefore, dealing with all this logic in the playlist editor is summed up to a single function call, dismissing the need of keeping track of values such as limit and offset:

```javascript
loadMorePlaylists = async () => {
    const { page } = this.state;
    const nextPage = await page.getNextPage(); // Sit back and let spotify-web-sdk handle the hard work!
    this.setState(prevState => {
        const playlists = prevState.playlists.concat(nextPage.items);
        return { playlists, page: nextPage };
    });
};
```

The whole point of the application is to let users sort their playlists, so let's get to it. From the *PlaylistPage*, the user can select a sorting method (release date included!). Initially, the expected order of the tracks is defined and then sequential operations are done to reorder them. This is more or less how it works in code:

```javascript
import { reorderPlaylistTracks } from 'spotify-web-sdk';

export const sortPlaylistTracksByAttribute = async (
    playlistId: string,
    attribute: string
) => {
    let insertionOrder = await getInsertionOrder(playlistId, attribute);
    return insertionOrder.reduce(async (previousPromise, current) => {
        await previousPromise;
        return moveTrackToTop(playlistId, current);
    }, Promise.resolve());
};

const getInsertionOrder = async (
    playlistId: string,
    attribute: string
) => { /* Determines the insertion order based on the attribute. */ };

const moveTrackToTop = (id: string, oldIndex: number) =>
    reorderPlaylistTracks(id, oldIndex, { rangeLength: 1, insertBefore: 0 });
```

BTW, if you're not familiar with this approach of resolving Promises sequentially using *Array.prototype.reduce()*, there's a great article about how it works and, most importantly, **why** it works. Check it out on [CSS Tricks](https://css-tricks.com/why-using-reduce-to-sequentially-resolve-promises-works/)!

If you'd like to see more details, I think that the commit log can be a good guide on what was added and when, since I try to make descriptive and succinct commit messages. **Spotify Playlist Editor** is also live right [here](https://calluswhatyouwant.github.io/spotify-playlist-editor/) if you want to play around a bit. If you come across anything unexpected, please, create an issue in the project's GitHub repository. PRs are also welcome and we do have a few issues already open, so suit yourself!

{% github https://github.com/calluswhatyouwant/spotify-playlist-editor %}

---

This is it for the part one of the **Meet spotify-web-sdk!** series. What do you think? Let us know in the comments! If you're interested in knowing what we're up to, you can [find us on Twitter](https://twitter.com/CallUsWhat).

Thank you so much for reading and see you next time! 😉