Jammming - 403 error when creating a playlist (async-await)

Hi All,

I’m a bit stumped on the project, I’ve gone over my code and looked at a few solutions on the forums and I think my syntax is correct, but I’ve been starring at it for too long and could really use a fresh set of eyes.

I’m currently on step 93 of the Jammming Project. I have opted for the async-await approach rather than the chained .then() and I’m not sure if this is what is causing the issue.

From what I can see the error I’m getting is a 403 error, the documentation says

Bad OAuth request (wrong consumer key, bad nonce, expired timestamp…). Unfortunately, re-authenticating the user won’t help here.

Here is the code for my Spotify.js (I’m only including the .savePlaylist() method as this is all that’s changed in my code base

async savePlaylist(name, trackURIs) {
    if (!name && !trackURIs) {
      console.log(`No name or Track URI's were found`);
      return;
    }
    const accessToken = this.getAccessToken()
    const headers = {
      Authorization: `Bearer ${accessToken}`,
      "Content-Type": "application/json",
    };

    // fetch User ID
    let userID = "";
    const endpoint = "https://api.spotify.com/v1/me";

    let response = await fetch(endpoint, {
      headers: headers,
    });

    if (response.ok) {
      const user = await response.json();
      userID = user.id;
    }

    // create a new playlist
    const playlistEndpoint = `https://api.spotify.com/v1/users/${userID}/playlists`;

    response = await fetch(playlistEndpoint, {
      method: 'POST',
      headers: headers,
      body: JSON.stringify({name: name})
    });

    if (response.ok) {
      const playlist = await response.json();
      console.log(playlist); // testing for the response 
    }
    throw new Error('Could not create new playlist')
  },

When I paste the playlistEndpoint URL into my browser I get an error saying that the access token is missing but I’m assuming that’s because I have pasted it straight into my browser.

I have found the solution to this, if you’re interested I’ve posted my refactor code below.

TLDR; I was missing the scope parameter, as I created my own endpoint instead of using the one provided by codeacademy. But what they don’t explain is that the scope is important as you’ll need it to be able to create your playlist.

// URL setup
const base = "https://accounts.spotify.com/authorize";
const response_type = "token";
const scope = "playlist-modify-public";
const redirect_uri = "http://localhost:3000/";
const client_id = "b3572cb44b614c32b3f02bd25673dff0";

let endpoint = base;
endpoint += `?response_type=${response_type}`;
endpoint += `&client_id=${client_id}`;
endpoint += `&scope=${scope}`;
endpoint += `&redirect_uri=${redirect_uri}`;

With this included as part of the access token request, I could now create playlists. This a small but important detail.

I’ve seen a lot of students use the .then() method of fetching these requests. I used async await as I believe it’s more common practice (so I’m told). If you’re interested to see how I created that I’ve included my code below. For DRY purposes i was able to create a request method that encapsulated the fetch() request.

async request(url, args) {
    try {
      const response = await fetch(url, args);

      if (response.ok) {
        return response.json();
      }
    } catch (e) {
      console.error(e.message);
    }
  }

now I can just call the .request(url, args) whenever I’m doing fetch request and it will handle the request and any errors it may encounter along the way. This is what the rest of my code looks like

async search(searchTerm) {
    const foundTracks = await this.request(
      `https://api.spotify.com/v1/search?type=track&q=${searchTerm}`,
      {
        headers: { Authorization: `Bearer ${this.getAccessToken()}` },
      }
    );

    let tracks = [];
    if (foundTracks.tracks) {
      tracks = foundTracks.tracks.items.map((track) => {
        return {
          id: track.id,
          name: track.name,
          artist: track.artists[0].name,
          album: track.album.name,
          uri: track.uri,
        };
      });
    }
    return tracks;
  },

  async savePlaylist(name, trackURIs) {
    const apiEndpoint = "https://api.spotify.com/v1/";

    if (!name && !trackURIs) {
      console.log(`No name or Track URI's were found`);
      return;
    }
    const accessToken = this.getAccessToken();
    const headers = {
      Authorization: `Bearer ${accessToken}`,
    };

    // fetch User ID
    const user = await this.request(`${apiEndpoint} + me`, {
      headers: headers,
    });

    // create a new playlist
    const playlist = await this.request(`${apiEndpoint}users/${user.id}/playlists`, {
      method: "POST",
      headers: headers,
      body: JSON.stringify({ name: name }),
    });

    console.log(playlist);
  }
1 Like

Tks for sharing your solution. I had the same problem and spent a long time trying to solve it until I saw your solution :slight_smile:

1 Like