I’ve been trying to get the album cover art to replace the objects that are rendered on the page meant for the album image to be placed in. I have been trying to figure out the json path name for example data.album.name
or album.image
but I can’t seem to figure it out. I ran the API calls using Insomnia and I get the same data as shown in the example page from the how-to documentation from Spotify, but I can’t get the data to render on the page. I’m not sure what I’m doing wrong, any good hints or resource that can be provided will be appreciated. I been stuck on this for the past 10 hours. I’ve included a link to the gist for the main files and here is the tree structure of my main files.
└── mySpotifyModule
├── node_modules
├── package.json
├── package-lock.json
├── public
│ ├── index.html
│ └── spotify-bg.png
└── src
├── App
│ ├── App.css
│ └── App.js
├── index.css
├── index.js
├── Play
│ └── Playlist.js
├── script.js
├── Search
│ ├── SearchBar.css
│ ├── SearchBar.js
│ └── SearchResults.js
├── styles.css
└── Track
├── Track.js
└── Tracklist.js
App.js
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";
import { Container, InputGroup, FormControl, Button, Card, Row } from "react-bootstrap";
import { useState, useEffect } from "react";
const CLIENT_ID = '684f2f7c27fc4e6eac20d56f7b4da9fe'
const CLIENT_SECRET = '256582d4f9d04a7f82631a7ec7cf5945'
function App() {
const [searchInput, setSearchInput] = useState("");
const [accessToken, setAccessToken] = useState("");
const [albums, setAlbums] = useState([]); //Taylor Swift
useEffect(() => {
// API Access Token
var authParameters = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'grant_type=client_credentials&client_id=' + CLIENT_ID + '&client_secret=' + CLIENT_SECRET
}
fetch('https:///accounts.spotify.com/api/token', authParameters)
.then(results => results.json())
.then(data => setAccessToken(data.access_token))
}, [])
// Search
async function search() {
console.log("Search for " + searchInput); //Taylor Swift
var searchParameters = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
}
}
var artistID = await fetch('https://api.spotify.com/v1/search?q=' + searchInput + '&type=artist', searchParameters)
.then(response => response.json())
.then(data => data.artists.items[0].id)
console.log("Artist ID is " + artistID);
// Get request with Artist ID grab all the albums from that artist
var returnedAlbums = await fetch('https://api.spotify.com/v1/artists/' + artistID + '/albums' + '?include_groups=album&market=US&limit=50', searchParameters)
.then(response => response.json())
.then(data => {
console.log(data.items);
setAlbums(data.items);
});
// Display all the albums
}
console.log(albums);
return (
<div className="App">
<Container>
<InputGroup className="mb-3" size="lg">
<FormControl
placeholder="Search for an artist"
type="input"
onKeyDown={event => {
if (event.key === "Enter") {
search();
}
}}
onChange={event => setSearchInput(event.target.value)}
/>
<Button onClick={() => { console.log("Clicked Button") }}>
Search
</Button>
</InputGroup>
</Container>
<Container>
<Row className="mx-2 row row-cols-4">
{albums.map((album, i) => (
<Card key={i}>
<Card.Img src={album.images[0]} />
<Card.Body>
<Card.Title>Album Name Here</Card.Title>
</Card.Body>
</Card>
))}
</Row>
</Container>
</div>
);
}
export default App;
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Spotify Profile</title>
</head>
<body>
<div id="root"></div>
<div className="header">
<section id="profile">
<h2>Logged in as: <span id="displayName"></span></h2>
<span id="avatar"></span>
</div>
<ul>
<li>User ID: <span id="id"></span></li>
<li>Email: <span id="email"></span></li>
<li>Spotify URI: <a id="uri" href="#"></a></li>
<li>Link: <a id="url" href="#"></a></li>
<li>Profile Image: <span id="imgUrl"></span></li>
</ul>
</section>
<script src="src/App/App.js"></script>
</body>
</html>
package.json
{
"name": "react",
"version": "1.0.0",
"description": "React example starter project",
"keywords": [
"react",
"starter"
],
"main": "src/index.js",
"dependencies": {
"allow-cors": "^1.0.0",
"bootstrap": "^5.3.0",
"cors": "^2.8.5",
"loader-utils": "3.2.1",
"nextjs-cors": "^2.1.2",
"react": "^18.2.0",
"react-bootstrap": "^2.8.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"row": "^0.0.1"
},
"devDependencies": {
"@babel/runtime": "7.13.8",
"@types/react-dom": "^18.2.6",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"npm-run-all": "^4.1.5",
"typescript": "4.1.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"server": "node server",
"dev": "run-p server start",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"author": "",
"license": "ISC"
}
index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App/App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<App />
</StrictMode>
);
script.js
const clientId = "684f2f7c27fc4e6eac20d56f7b4da9fe";
const params = new URLSearchParams(window.location.search);
const code = params.get("code");
const accessToken = "BQDdu7TSgqbktAc0PhtubsQLrpuXRd60h2OhRHEQKECVoj-ILdJDzUEu3r6sDUXqqSdHZ5LBbii_LDp4nqvdNOeXdDmUCVajexl4TmsIiDuB2HLZm-g"
if (!code) {
redirectToAuthCodeFlow(clientId);
} else {
getAccessToken(clientId, code)
.then(accessToken => fetchProfile(accessToken))
.then(profile => populateUI(profile))
.catch(err => console.error(err));
}
async function redirectToAuthCodeFlow(clientId) {
const verifier = generateCodeVerifier(128);
const challenge = await generateCodeChallenge(verifier);
localStorage.setItem("verifier", verifier);
const params = new URLSearchParams();
params.append("client_id", clientId);
params.append("response_type", "code");
params.append("redirect_uri", "http://localhost:5173/callback");
params.append("scope", "user-read-private user-read-email");
params.append("code_challenge_method", "S256");
params.append("code_challenge", challenge);
document.location = `https://accounts.spotify.com/authorize?${params.toString()}`;
}
function generateCodeVerifier(length) {
let text = '';
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
async function generateCodeChallenge(codeVerifier) {
const data = new TextEncoder().encode(codeVerifier);
const digest = await window.crypto.subtle.digest('SHA-256', data);
return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
}
async function getAccessToken(clientId, code) {
const verifier = localStorage.getItem("verifier");
const params = new URLSearchParams();
params.append("client_id", clientId);
params.append("grant_type", "authorization_code");
params.append("code", code);
params.append("redirect_uri", "http://localhost:5173/callback");
params.append("code_verifier", verifier);
const result = await fetch("https://accounts.spotify.com/api/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params
});
const { access_token } = await result.json();
return access_token;
}
async function fetchProfile(token) {
const result = await fetch("https://api.spotify.com/v1/me", {
method: "GET",
headers:
{
'Content-Type': 'application/json',
'Authorization': 'Bearer '+ token
}
});
return result.json();
}
function populateUI(profile) {
// Update UI with profile data
document.getElementById("displayName").innerText = profile.display_name;
if (profile.images[0]) {
const profileImage = new Image(200, 200);
profileImage.src = profile.images[0].url;
document.getElementById("avatar").appendChild(profileImage);
document.getElementById("imgUrl").innerText = profile.images[0].url;
}
document.getElementById("id").innerText = profile.id;
document.getElementById("email").innerText = profile.email;
document.getElementById("uri").innerText = profile.uri;
document.getElementById("uri").setAttribute("href", profile.external_urls.spotify);
document.getElementById("url").innerText = profile.href;
document.getElementById("url").setAttribute("href", profile.href);
}