Jammming project - Can't save the playlist to my account - 400 Error (BAD REQUEST)

Hello, I’m having troubles to save the playlist to my account, as I’m getting the 400 Error when saving it. Also, the playlist title isn’t refreshing.

Here is my Spotify.js

const clientId = ""; // deleted for this post
const redirectUri = "http://react-app-jammming.surge.sh";

let accessToken;

export const Spotify = {
    getAccessToken() {
        if (accessToken) {
            return accessToken;
        }

        // check for an access token match - match() return an array with the values found
        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, allowing us to grab a new access token when it expires
            window.setTimeout(() => accessToken = '', expiresIn * 1000);
            window.history.pushState('Access Token', null, '/');

            return accessToken;
        } else {
            const accessUrl = `https://accounts.spotify.com/authorize?client_id=${clientId}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectUri}`;
            window.location = accessUrl;
        }
    },

    search(term) {
        const accessToken = Spotify.getAccessToken();

        return fetch(`https://api.spotify.com/v1/search?type=track&q=${term}`, 
            { headers: {
                Authorization: `Bearer ${accessToken}`
        }}).then(response => {
            return response.json();
        }).then(jsonResponse => {
            // if nothing comes from SPOTIFY API then return an empty array
            if (!jsonResponse) {
                return [];
            }

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

    savePlaylist(name, trackUris) {
        if(!name || !trackUris.length) {
            return;
        }

        const accessToken = Spotify.getAccessToken();
        const headers = { Authorization: accessToken };
        let userId;

        return 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: name })
                    }).then(response => response.json())
                        .then(jsonResponse => {
                            const playlistId = jsonResponse.id;

                            return fetch(`https://api.spotify.com/v1/users/${userId}/playlists/${playlistId}/tracks`, 
                            {
                                headers: headers,
                                method: "POST",
                                body: JSON.stringify({ uris: trackUris })
                            });
                        });
                }).catch(err => console.log(err));
    }
}

And here is my App.js

import React from "react";
import ReactDOM from "react-dom";
import './App.css';
import { SearchBar } from "../SearchBar/SearchBar";
import { SearchResults } from "../SearchResults/SearchResults";
import { Playlist } from "../Playlist/Playlist";

import { Spotify } from "../../util/Spotify";

class App extends React.Component {
	constructor(props) {
		super(props);
		this.addTrack = this.addTrack.bind(this);
		this.removeTrack = this.removeTrack.bind(this);
		this.updatePlaylistName = this.updatePlaylistName.bind(this);
		this.savePlaylist = this.savePlaylist.bind(this);
		this.search = this.search.bind(this);
		this.state = { 
			searchResults: [],
			playlistName: "My Playlist",
			playlistTracks: []
		}
	}

	addTrack(track) {
		let tracks = this.state.playlistTracks;

		if (tracks.find(savedTrack => savedTrack.id === track.id )) {
			return;
		}

		tracks.push(track);
		this.setState( { playlistTracks: tracks } );
	}

	removeTrack(track) {
		let tracks = this.state.playlistTracks;

		tracks.splice(tracks.indexOf(track.id), 1);

		this.setState( { playlistTracks: tracks } );
	}

	updatePlaylistName(newPlaylistName) {
		this.setState({ playlistName: newPlaylistName});
	}

	savePlaylist() {
		const trackUris = this.state.playlistTracks.map(track => track.uri);

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

	search(searchTerm) {
		Spotify.search(searchTerm).then(searchResults => {
			this.setState({ searchResults: searchResults })
		})
	}

	render() {
		return (
		<div>
			<h1>Ja<span className="highlight">mmm</span>ing</h1>
			<div class="App">
				<SearchBar onSearch={this.search} />
				<div className="App-playlist">
					<SearchResults searchResults={this.state.searchResults} 
						onAdd={this.addTrack} />
					<Playlist playlistName={this.state.playlistName} 
						playlistTracks={this.state.playlistTracks} 
						onRemove={this.removeTrack} 
						onNameChange={this.updatePlaylistName} 
						onSave={this.savePlaylist} />
				</div>
			</div>
		</div>
		);
	}
}

ReactDOM.render(<App />, document.getElementById("root"))
export default App;

I managed to do everything as the video, but having this 400 Error in my fetch’s in “savePlaylist” method, getting “undefined” for my variables: “userId” & “playlistId”.

Do you have experimented something similar? I can’t understand what is going on, because everything else works as expected!!

Thank you very much. Kind regards, Andy.-

Hello, and welcome to the forums!

You may be able to click the small triangle to the left of the error message to expand it and see more information. I know the Spotify APIs often send back more details that may or may not be in the console for error 400s. Sometimes it requires capturing the error response in your code and examining it from there though.

One thing I do notice in your Spotify.js is the difference in headers being created in your search() and savePlaylist() methods:

1 Like

OMG!! I can’t believe that was the solution… I’m really sorry about such a dumb error… Is just this Spotify module was a real challenge. AJAX and APIs is still a real challenge for me.

No words to thank you!!! You gave me hope :innocent: :star_struck: :pray: :mechanical_arm:

1 Like

This wasn’t a dumb error at all! Making these kinds of mistakes is what helps us learn and reinforce our knowledge. Plus, we got to see the chain reaction of one mistake showing up in odd ways. It’s one of the reasons I like helping in the forums in the first place

1 Like