Thanks for the response. That helped a lot. The redirect process in that authorization handshake to get the access token really confused me. I am used to passing request data via urls, but I had never encountered receiving response data via urls as well. It makes a bit more sense to me now.
So I was able to get all the way through the rest of the project, but I am still stuck on that url to get the access token. This is weird because I actually had that part working when I just copy pasted the URL into the browser directly, it gave me the proper redirect for authorization. But now it doesn’t work for some reason. Now, when I paste the URL directly in to test it, it gives me a page with only the error message: “INVALID_CLIENT: Invalid redirect URI”. It seems to suggest something wrong with the redirect URI, but I cannot find any issue, it follows Codecademy’s instructions. I have added the matching information in the application dashboard settings as the redirect URI as well.
I thought maybe it needed the URL encoding by using the encodeURIComponent() method since the Spotify API docs say to use it, and that is what I did last time when it worked I think. But that didn’t help either.
I am also a little suspicious of possible changes to the Spotify API that may no longer align with Codecademy’s instructions. A couple of things I could not confirm in the docs. For example, this line of code:
const headers = { Authorization: `Bearer ${accessToken}` }
That comes from Codecademy’s hint after #86. I have no idea why the token has to be formatted that way with "Bearer " in front of it. I did not see anything regarding that in the API docs.
Also, the Spotify endpoint for creating a new playlist in a user’s account has changed from what Codecademy states. Codecademy’s hint after #94 states it is at: /v1/users/{user_id}/playlists/{playlist_id}/tracks. But per the Spotify API doc at Web API Reference | Spotify for Developers, the endpoint is really at: https://api.spotify.com/v1/playlists/playlist_id/tracks. At least as far as I am understanding it anyway.
Little doubts and uncertainty about several things like that are making it difficult for me to troubleshoot my way out of being stuck as I can’t narrow down issues very well.
I think I am really close, but I am just not sure what else to try to get it to work. My code for my Spotify.js module now looks like the below. It has code for the future steps filled out, but I am just focused on getting the getAccessToken() method to work, rather than worrying about the other methods.
What I currently have now for the getAccessToken() method right now also doesn’t fully make sense to me. In particular, the last conditional if-statement block. If I don’t have the access token already, then I redirect the browser to the constructed URL to make the authorization request. If I am understanding this correctly, that redirect will take the user to a Spotify authorization dialog popup asking the user to authorize the app. Then if the user approves the authorization, they will get redirected back to my app’s page, with their access token and expiration appended to the end of the URL (i.e. a "hash fragment). However, the first time this method is called before the access token is set, it will skip the first 2 conditions and go to the 3rd condition, which will give me the access token, but not actually capture and save it, which is what the 2nd conditional is needed for. And it won’t return it either, which is what the 1st conditional is for. It seems to me almost like the 2nd and 3rd conditional if-statement blocks in the method need another recursive call to getAccessToken() at the bottom of each of them. It also seems to me like getAccessToken() should be an async function to accommodate the delays. But what I have here is how I read the actual instructions.
Clearly, I am missing something here. Any ideas?
Any help is greatly appreciated, thanks.
const CLIENT_ID = '00f8e8f9bfcb4f05a7ee95c8d6626261';
const REDIRECT_URI = 'http://localhost:3000/';
let accessToken = '';
const Spotify = {
getAccessToken: () => {
if (accessToken) {
return accessToken;
}
if (window.location.href.match(/access_token=([^&]*)/) &&
window.location.href.match(/expires_in=([^&]*)/)) {
accessToken = window.location.href.match(/access_token=([^&]*)/)[1];
let expiresIn = window.location.href.match(/expires_in=([^&]*)/)[1];
window.setTimeout(() => accessToken = '', expiresIn * 1000);
window.history.pushState('Access Token', null, '/');
}
if (!accessToken && !window.location.href.match(/access_token=([^&]*)/)) {
window.location.href = `https://accounts.spotify.com/authorize?client_id=${CLIENT_ID}&response_type=token&scope=playlist-modify-public&redirect_uri=${REDIRECT_URI}`;
}
},
search: async(term) => {
const headers = { Authorization: `Bearer ${accessToken}` }
let searchResult = await fetch(`https://api.spotify.com/v1/search?type=track&q=${term}`, { headers: headers });
searchResult = await searchResult.json();
searchResult = searchResult.tracks.items;
return searchResult;
},
savePlaylist: async(name, tracks) => {
if (!name || !tracks) {
return;
}
const currentAccessToken = this.getAccessToken();
const headers = { Authorization: currentAccessToken };
let body = { name: name };
let userID = '';
let response = await fetch('https://api.spotify.com/v1/me', { headers: headers });
response = await response.json();
userID = response.id;
response = await fetch(`https://api.spotify.com/v1/users/${userID}/playlists`, { method: 'POST', headers: headers, body: body });
response = await response.json();
let playlistID = response.id;
body = { uris: tracks };
response = await fetch(`https://api.spotify.com/v1/playlists/${playlistID}/tracks`, { method: 'POST', headers: headers, body: body });
response = await response.json();
playlistID = response.id;
}
};
export { Spotify };