Jamming - 401 Error - Playlist Saves But Not Tracks

I’m working on the Jamming project and stuck on the last couple steps. I can search, add songs to my playlist, and save the playlist to my Spotify account - BUT when I click “Save To Spotify” I get the error:

“TypeError: Cannot read property ‘then’ of undefined”

And in the console:

“Failed to load resource: the server responded with a status of 401 ()”

401 = Unauthorized - The request requires user authentication or, if the request included authorization credentials, authorization has been refused for those credentials.

I’ve logged a bunch of the variables into the console and I can see my access token, user ID, the array of tracks, the Playlist ID, and Playlist Name.

The fact that I’m able to search and save the playlist itself makes me believe that I have a valid access token - which makes the 401 even more confusing. The playlist also saves to my Spotify account - but without any tracks.

I’ve also updated my endpoints based on the latest Spotify API updates. I’ve followed along with the video walkthrough and I still can’t figure out what I’m doing wrong.

Any help would be much appreciated. Here is the code for the savePlaylist method in ‘Spotify.js’:

savePlaylist(playlistName, playlistTracks) {
        if(!playlistName || !playlistTracks.length) {
            return;
        }

        const accessToken = Spotify.getAccessToken();

        const headers = { Authorization: `Bearer ${accessToken}`};
        let userId;

        userId = fetch('https://api.spotify.com/v1/me', { headers: headers }
        ).then(response => response.json()
        ).then(jsonResponse => {
            userId = jsonResponse.id;
            return fetch(`https://api.spotify.com/v1/users/${userId}/playlists`, 
            { 
                headers: headers,
                method:  'POST',
                body: JSON.stringify({name: playlistName})
            }).then(response => response.json()
            ).then(jsonResponse => {
                const playlistId = jsonResponse.id;
                return fetch(`https://api.spotify.com/v1/playlists/${playlistId}/tracks`, 
                {
                    header: headers,
                    method: 'POST',
                    body: JSON.stringify({uris: playlistTracks})
                });
            });
        });
    }

Hi @rchadek
you forgot to pass the userId in your last request.

Hi @mirja_t
Thanks for your reply. I originally had it in there - but doing some research it appears that the ‘tracks’ endpoint no longer requires it - as of 9/11/18. See articles below. Let me know what you think. Thanks

Yes, you’re right. It works indeed without the user id in the URL.

This isn’t closed correctly before you add the next chain.
And you have a typo in your last header (s).

@miraja_t - I got it working - to where I was able to save the playlist AND tracks! Thank you for your help.

One other question - there still seems to be an issue with the savePlaylist method in ‘App.js’. My guess is the Promise is not being returned correctly.

The playlist now successfully gets created - including tracks - in my Spotify account. However, my application is redirected to an error page: “TypeError: Cannot read property ‘then’ of undefined”

It looks like it has to do with this statement:

Spotify.savePlaylist(this.state.playlistName, trackURIs).then(() => {
      this.setState({
        playlistName: 'New Playlist',
        playlistTracks: []
      })
    })

So I’m guessing that the savePlaylist method is not returning a Promise - so the ‘.then()’ is undefined - but how would I go about troubleshooting this?

You don’t return from the function savePlaylist in Spotify.js.
You declare userId here

Then you assign the value here

Here you don’t need to do it:

You could just return that.

@mirja_t - thank you so much! Adding the keyword ‘return’ before the ‘userId = fetch’ statement eliminated the error screen on playlist save.

I have one other question I thought you might be able to help point me in the right direction:

The first time I go to ‘localhost:3000’ and perform a search, it briefly shows my search results, then it appends ‘#access_token=’ and the token value to the URL - but the search results disappear and I have to perform the search again. Any search after that - as long as I don’t close the tab - works perfectly.

I’m guessing this is because it’s setting ‘window.location’ to the accessURL - but do you have any guess as to why the search results disappear only after the initial search?

It doesn’t seem like the app is behaving in this way on the video walkthrough. Thoughts?

Here’s the code to the ‘getAccessToken’ method in ‘Spotify.js’:

getAccessToken() {
        if (accessToken) {
            return accessToken;
        }

        // check for access token match
        const accessTokenMatch = window.location.href.match(/access_token=([^&]*)/);
        const expiresInMatch = window.location.href.match(/expires_in=([^&]*)/);

        if(accessTokenMatch && expiresInMatch) {
            accessToken = accessTokenMatch[1];
            const expiresIn = Number(expiresInMatch[1]);

            // This clears the parameters and allows us to grab a new access token when it expires
            window.setTimeout(() => accessToken = '', expiresIn * 1000);
            window.history.pushState('AccessToken', null, '/');
            return accessToken;
        }
        else {
            const accessUrl = `${authorizationURI}client_id=${clientID}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectURI}`;
            window.location = accessUrl;
        }

    },

Haha. I’ve got exactly the same bug in my own code. Except that I don’t see the results at all on first try. It’s like I have to wake up the connection somehow.

Actually I haven’t put any effort in solving that yet. Everything after the first try works perfectly. So, when I find out I’ll keep you updated. And vice-versa if you do, please :slight_smile:

@mirja_t - sounds good. I will let you know if I figure it out. Thanks so much for all your help!

1 Like