DEV Community

Cover image for Using spotify-web-sdk to handle requests to the Spotify Web API
Robson Junior for Call Us What You Want

Posted on

Using spotify-web-sdk to handle requests to the Spotify Web API

This is the first post of the Meet spotify-web-sdk! series, in which we (Call Us What You Want) 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 that uses Spotify Web API to retrieve information and manage a user's data.

GitHub logo calluswhatyouwant / spotify-web-sdk

A JS SDK for the Spotify Web API.

Spotify Web SDK

A JavaScript SDK for the Spotify Web API Note that this project is still a BETA version.

Table of Contents

Features

"Why should I use this?"

We want to handle the hard work for you Even to make simple requests, such as to get information on a track, you'd need to make a bunch of setups Here is how you could do the same thing with our aid:

import * as spotify from 'spotify-web-sdk';
spotify.init({ token: 'YOUR SPOTIFY TOKEN HERE!' }); // You should only need to run this once.
spotify.getTrack('3LOpHuEpjkL4T1Zcjhko8w'); // Or any other track id.
Enter fullscreen mode Exit fullscreen mode

Yes, it's as simple as that!

"I still think it's no hard work at all.

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

ME! and The Other Side are both singles but also show up in my Spotify library as albums.

I came up with a seemingly simple solution: I created a playlist 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. 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. 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), 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 and another one that can be used to reorder a track or a block of 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

Visualization of how the "reorder a playlist's tracks" endpoint works. Source: Spotify for Developers

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!

Spotify Playlist Editor

Once logged in, something like that should appear to you.

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, 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.

I included some packages and toolkits to simplify the coding process (for instance, Bootstrap so that I could worry less about styles and prettier to help keep the code neat). I think it's worth mentioning I'm using Flow 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

Also, React + Flow + IntelliSense is a dream combo.

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:

/* @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> {
    // ...
}
Enter fullscreen mode Exit fullscreen mode

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:

componentDidMount = async () => {
    const page = await getCurrentUserPlaylists({ limit: 5 });
    this.setState({
        page,
        playlists: page.items,
    });
}
Enter fullscreen mode Exit fullscreen mode

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:

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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:

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 };
    });
};
Enter fullscreen mode Exit fullscreen mode

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:

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 });
Enter fullscreen mode Exit fullscreen mode

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!

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 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 logo calluswhatyouwant / spotify-playlist-editor

Sort your Spotify playlists any way you want.

Spotify Playlist Editor

Sort your Spotify playlists anyway you want! 🛠

Initial page

Table of Contents

Features

  • Create new playlists out of your recent Spotify tracks or your all-time top tracks;
  • Sort playlists based on
    • playlist track attributes (addition date);
    • track attributes (name, length, popularity);
    • album attributes (name, release date);
    • artist attributes (name).

Current limitations

  • It's highly recommended to create a copy of the playlists you want to edit or to use one of the playlist creation options. (play around, but do it safely!);
  • You can only sort playlists with 100 tracks or less;
  • Sorting might take a while (a playlist with 100 tracks can take between 30 seconds and 1 minute). Do NOT reload or close the playlist page until sorting is over.

Community

Installation and Usage

Simply run yarn install to install the project's dependencies…


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.

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

Discussion (0)