A15 – Using spotify-web-api.js

Part I

  1. Download the Spotify-web-api.js library from https://raw.githubusercontent.com/JMPerez/spotify-web-api-js/master/src/spotify-web-api.js and upload it your server. Place it is a subdirectory of your site’s root directory (e.g. /javascript).
  2. Download the require.js library from https://requirejs.org/docs/release/2.3.6/minified/require.js and upload it to your server. Place it is a subdirectory of your site’s root directory (e.g. /javascript).
  3. Create a web page named elvis_pics.html in your …/csci240 directory and a file named elvis_pics.js in your …/csci240/javascript directory.
  4. Create a Spotify account if you haven’t already.
  5. Read my tutorial named Spotify for Developers and register your web application (i.e. elvis_pics.html).
  6. Read my tutorial named Using Require.js and add a single <script> tag to your elvis_pics.html file so that require.js is loaded first and then your elvis_pics.js file is loaded.
  7. Edit your elvis_pics.js file so that require.js loads the spotify-web-api.js file in your /javascript directory as well as the d3.js JavaScript module found at https://d3js.org/d3.v5.min.js. Pass a function named main to requirejs().
  8. In your elvis_pics.js file, declare a function named main and in it, print something to the console. Verify that main() is executed by navigating to your web app using Chrome, Firefox or Opera, open the Developer tools, and verify that main() was executed by checking the console.
  9. Add code to main() that uses d3.js to append a visual element to the web page. Verify that the d3 code in main() is working properly by navigating your browser to your web app.

Part II

Rewrite your main function so that it communicates with Spotify’s authorize endpoint and retrieves data from from Spotify using the spotify-web-api.js library. Your main function should be structured as follows.

function main(spotty, d3) {
    // Detect when the user has navigated to the website
    if (window.location.hash.length == 0) {
        //compose a url for the Spotify authorize endpoint

        window.location = new_loc;
    }

    // Parse window.location.hash to get the access token

    // Instantiate the spotify-web-api constructor

    // Set the access token

    // Make 3 requests for data from Spotify and do something 
    // visual with the data when it is received.

}

Instructions on how to compose the URL for the Spotify authorize endpoint and parse the hash string can be found in the tutorial named Spotify for Developers.

Instructions on how to instantiate the spotify-web-api constructor and set the access token can be found in the tutorial named Using spotify-web-api.js.

Using spotify-web-api.js

The Spotify documentation provides a list of wrapper libraries for a variety of languages. One of the JavaScript libraries listed is named spotify-web-api.js. This tutorial will show how to use spotify-web-api.js to download the meta data for all of Elvis’ albums and then display all of the album covers for those albums.

Prerequisites

In this tutorial, we assume that you have the spotify-web-api.js file loaded in the browser. For information on how to load the file using require.js see the tutorial named Using Require.js. We also assume that you’ve registered your web app with Spotify, have set the application’s redirect URI, and requested user permissions, and have received an access token. Please see the tutorial named Spotify for Developers for information on how to accomplish all of that.

Instantiating the spotify-web-api Wrapper

Before you can request information you need to instantiate the spotify-web-api wrapper. You do so by calling the SpotifyWebApi constructor.

let spotifyApi = new SpotifyWebApi();

Next, you need to register your access token.

spotifyApi.setAccessToken(params.access_token);

Getting Data From Spotify

The example below is taken directly from the spotify-web-api.js GitHub website. It retrieves all of the album information for Elvis using the JavaScript Promise pattern.

// get Elvis' albums, using Promises through Promise, Q or when 
spotifyApi.getArtistAlbums('43ZHCT0cAZBISjO8DG9PnE')   
.then(function(data) {
    // use the data as you see fit
    console.log('Artist albums', data);
}, function(err) {     
    console.error(err);   
});

Using Require.js

Require.js is a Javascript library that allows you to load multiple JavaScript files and JavaScript modules. The website for the library is at https://requirejs.org.

Our Running Example

Note first that this tutorial shows only one use for require.js. It is very versatile and can be used in many other use cases. So if your situation is not identical to this one, please consult the require.js documentation.

In this tutorial we assume that we have the following JavaScript files on our server.

/javascript/spotify-web-api.js
/javascript/require.js

/.../demos/spotify_demo.html
/.../demos/javascript/spotify_demo.js

We also assume that our web app (spotify_demo.html) runs spotify_demo.js and that spotify_demo.js needs to load both spotify-web-api.js and the d3 JavaScript module found at https://d3js.org/d3.v5.min.js.

Installing require.js

You can install require.js on your site by downloading the require.js file at https://requirejs.org/docs/release/2.3.6/minified/require.js and then uploading it to your server.

Since you’re likely to use require.js in multiple pages on your website, it is advantageous to upload the file to a location on your server that is easily accessible by all of your web pages. I recommend creating a subdirectory of your website’s root directory, as our example illustrates, and placing it there.

Loading require.js

Since spotify-demo.js will call some of the functions in require.js to load the other JavaScript files, we need to load require.js before spotify-demo.js.

You can load both require.js and your webpage’s JavaScript file in a single <script> tag (as shown below). When you do this, your webpage’s JavaScript file (e.g. spotify-demo.js) will be loaded after require.js loads.

<script src="/javascript/require.js" data-main="javascript/spotify-demo"></script>

In the above example, the src attribute uses an absolute path. As stated above, we assume the require.js file in /javascript (a subdirectory of the site’s root directory) so that all of the web apps in the domain can use the require.js file. Notice we need to specify the .js file extension, as we do with every <script> tag, when specifying the require.js file name.

In the example above, the data-main attribute uses a relative path. The data-main attribute specifies the JavaScript file that will be loaded and executed after require.js is loaded. The require.js library will search for spotify-demo.js relative to the directory holding the html file that included the <script> tag. Note also that the .js file extension is not specified when using a relative path.

Using require.js

In our app’s JavaScript file (e.g. spotify-demo.js) we can load a JavaScript file (e.g. spotify-web-api.js) and a JavaScript module (@ https://d3js.org/d3.v5.min.js) by using the requirejs() function.

By default, requirejs() searches for the files to load in the same directory specified in the data-main attribute of the <script> tag. Since the script file specified in data-main (spotify-demo.js) is located in /…/demos/javascript/ and the script we want to load (spotify-web-api.js) is in /javascript, we need to tell requirejs() where to find spotify-web-api.js.

To do so, we need to call requirejs.config() before requirejs() to specify a base URL that requirejs() will use to find the JavaScript file.

requirejs.config({
  baseUrl: '/javascript'
});
requirejs(["spotify-web-api","https://d3js.org/d3.v5.min.js"], main);

function main(spotty, d3) {
    // files and modules have been loaded and are ready for use
    // spotty is undefined but d3 is not.
}

In the above example, we call requirejs.config() to specify the base URL that requirejs() will use to search for the internal JavaScript libraries and then call requirejs().

The first argument to requirejs() is an array of comma separated strings that list the names of the JavaScript files and modules to load. In the example above, we list an internal JavaScript file (spotify-web-api) and an external JavaScript module (https://d3js.org/d3.v5.min.js). Note that the name of the internal file (spotify-web-api) does not include the .js file extension and the external URL does.

The second argument is the name of a function that will be executed after the files and modules are loaded. When the main function is executed, references to the modules are passed to main. Since the first file loaded as an Immediately-Invoked Function Expression (IIFE) nothing is passed to main, but we need a placeholder variable none-the-less. Since the external JavaScript file is implemented as a module, a reference to the d3 object is stored in the parameter named d3 and ready to use inside main.

Spotify for Developers

Many think of Spotify as simply an app. It is better to think of Spotify as an internet content provider. They allow users to search and download the digital content on their servers, and create user profiles and playlists.

Like many internet service providers, they care less about which app you use to interface with their service, and care more about growing a user base which uses their service. To that end, they provide various libraries and APIs that allow independent IOS, Android, and Web applications to access their servers. Developer documentation for these resources can be found at https://developer.spotify.com.

The Spotify Web API

The Spotify Web API allows web site developers to push and pull data from the Spotify servers. This includes:

  • Information about artists, albums and tracks
  • User profile information and playlists
  • Music that users have saved in their Spotify music library

Registering Your Web App

In order to use the Web API we must first register our app with Spotify by navigating to the Spotify Dashboard and pressing CREATE A CLIENT ID. When registering an app, you will agree to Spotify’s terms of service, indicate the type of app you are creating (choose Website), and specify whether or not the app will be used for commercial purposes (choose Non-commercial).

After you have registered your app, you’ll notice a green box on the dashboard that includes a client id. We’ll use this id when sending authentication requests to the server.

When a user navigates to your Spotify web app, your app will redirect the browser to a Spotify authentication web page. The Spotify page will ask the user to log in. After the user logs in, Spotify will redirect the browser back to your site. To ensure that no one mischievous is using your client id, Spotify requires us to register the URL of our web app.

To register your web app’s URL, navigate back to the dashboard and click on your app’s green box. Then press EDIT SETTINGS. Scroll down to Redirect URI and add the URL for your web app.

Now that we’ve registered our app, it’s time to code.

Receiving User Authorization

Per the Spotify Authorization Guide, “calls to the Spotify Web API require authorization by your application user.” In this tutorial we are assuming you are creating a client-side application solely with JavaScript. In this case, we will use the Implicit Grant Flow to get the user’s authorization.

The Implicit Grant Flow requires you to send information about about your app and information about the permissions you are requesting from the user to https://accounts.spotify.com/authorize. You’ll do this by redirecting the browser. When the browser is redirect to the Spotify site, Spotify will display a user login screen and ask the user to grant your app the permissions you requested. If the user agrees, then Spotify will redirect the browser’s window back to your domain, specifically to the Redirect URI you specify. When the browser’s window is redirected back to your app, the URL will include an access token (and other information) in the fragment part of the URL. You will use the access token when requesting information from Spotify.

Redirecting to https://accounts.spotify.com/authorize

In order to receive authorization from the user, Spotify needs some information. Specifically, Spotify needs to know:

  • your client id
  • the URL that Spotify should redirect the browser back to if the user agrees to grant your app the permission your request
  • the types of permissions (also called scope)
  • a response type

This data is appended to https://accounts.spotify.com/authorize as a query string. In the example below we compose a query string and append it to the Spotify URL.

let host = "https://accounts.spotify.com/authorize";
let client_id = "abcdefghijklmnopqrstuvwxyz1234567890";
let redirect_uri = "http://n0code.net/work/teaching/courses/csci240/demo/spotify-elvis.html";
let scope = "user-read-private user-read-email";
let response_type = "token";

let new_loc = host +
  "?client_id=" + encodeURIComponent(client_id) +
  "&redirect_uri=" + encodeURIComponent(redirect_uri) +
  "&scope=" + encodeURIComponent(scope) +
  "&response_type=" + response_type;

Notice that when we concatenate the strings we call encodeURIComponent(). This replaces certain special characters in the string with escape sequences.

After we have a complete Spotify URL we can redirect the browser to the Spotify site using window.location.

window.location = new_loc;

When Spotify receives your request, the browser will display a Spotify login screen and permission request. If the user grants your app the permissions you requested, Spotify will redirect the browser to the URL you specified in the redirect_url string.

Getting the Access Token

When Spotify redirects the browser back to your site, it will include in the URL an access token and other information. That information will be included in the fragment part of the URL. You can get the fragment (a.k.a. hash) part from window.location.hash.

The hash contains the access token (and other information) as attribute-value pairs so you’ll need to parse the hash to get the access token. The code below separates the attribute-value pairs from the has and puts them in an object named params.

var hash = window.location.hash.substring(1);
var params = {};
hash.split('&').map(pair => {
  let temp = pair.split('=');
  params[temp[0]] = temp[1]
});

Your access token can now be accessed from params.access_token.

Super Quiz

  1. Declare a variable named arr that holds an array of 3 objects. Each object should holds information about a book and should contain a property named title that holds a string and a property named date_published that holds a number. Feel free to make up the data for the 3 objects.
  2. Write a function named printArray that takes an array as an argument and prints to the console the objects in the array, including each of the object’s properties and values. You may not simply pass the array to console.log.
  3. Write a function named insert that takes an array, a string, and an integer as arguments. The function should create a new object with title and date_published properties and set the property values using the string and integer that are passed into the function. The function should then add the new object to the array that was passed into the function.
  4. Add a new object using the insert function to the array that you created for problem 1. Call the printArray function to verify the new object is in the array.

Chapter 10 Review

  1. Create a function declaration named sumPair that returns the sum of the two arguments that are passed into it.
  2. Initialize two variables and pass them to sumPair. Print the result.
  3. Create a function expression named sumTriple that returns the sum of the three arguments that are pass to it.
  4. Initialize three variables and pass them to sumTriple. Print the result.
  5. Create an arrow function named sumQuad that returns the sum of the four arguments that are passed into it.
  6. Initialize four variables and pass them to sumQuad. Print the result.
  7. Create a function declaration named sumAll that returns the sum of the values in its arguments property.
  8. Call sumAll, passing to it 5 numbers. Print the result.
  9. Create a function named max that allows any number of arguments and returns the maximum value of the arguments that are passed into it. Set the first parameter’s default value to undefined, so that if no arguments are passed to max, undefined is returned.
  10. Call max with no arguments. Print the result.
  11. Call max with 3 arguments. Print the result.
  12. Declare an array named values that holds the values 2,4,6,8, and 10. Call max using the spread operator on values.
  13. Declare a function named min that allows any number of arguments and returns the minimum value of the arguments that are passed into it. Use a rest parameter to hold the values that are passed into the method. Return undefined if no arguments are passed to the function.
  14. Call min with no arguments. Print the result.
  15. Call min with 3 arguments. Print the result.