Spotify Api returning undefined object when trying to get playlist tracks with axios [closed] - javascript

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 months ago.
Improve this question
import axios from "axios";
import React, {useState, useEffect} from "react";
export default function Dashboard({token}) {
const [playlist_id, setPlaylistId] = useState([]);
const [href, setHref] = useState([]);
const [playlists, setPlaylists] = useState([]);
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
const getTracks = async (token) =>{
const {tracks} = await axios.get("https://api.spotify.com/v1/playlists/4FteCV6SQS8yKc6pzFlZnv/tracks", {
headers: {
Authorization: 'Bearer '+token
},
params: {
market: "US",
limit: 50,
offset: 0
}
})
console.log({tracks})
}
setIsMounted(true);
//getPlaylists(token);
getTracks(token);
}, [])
if(isMounted)
return(
<div className="Dashboard">
<h1>Hello</h1>
</div>
)};
I am trying to get the items in a public spotify playlist through axios, but the request retrieves an undefined object every time. Should I be using a different token with a special scope? Is there something I am missing with my API call?
These are the strings I am using to retrieve the original token:
const CLIENT_ID = "00c7cd96ee6940879762750970dc5863"
const REDIRECT_URI = "http://localhost:3000"
const AUTH_ENDPOINT = "https://accounts.spotify.com/authorize"
const RESPONSE_TYPE = "token"
I was able to make a similar call to retrieve all the playlists of a user and the response was const {data}

axios.get returns a Response object. That object doesn't have tracks property.
You probably wanted to do:
const {data: tracks} = axios.get(/* url */)

Related

React - axios fetching empty array [duplicate]

I am currently working on social media mern stack react app. I am using node js and express as my backend services , also using mongoose to store my data and axios and redux thunk which connect the backend to the front end. Till now I had no issue recieving and sending data to the server. Right now I am trying to create search post get request ,base on a keyword the user entered. The issue with it, that when I am sending the keyword to the server instead of recieving the string it gets undefined value, like redux thunk not sending anything. I will be very thankful if someone could help me with that. I am watching the code over and over again and can't find out the reason for that.
My post controller class(I copied only the relevant function):
import express from "express";
const app = express();
import Post from "../model/PostModel.js";
import ErrorHandlng from "../utilities/ErrorHandling.js";
import bodyParser from "body-parser";
import catchAsync from "../utilities/CatchAsync.js";
import User from "../model/UserModel.js";
app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
export const getPosts = catchAsync(async (req, res, next) => {
const data = req.body.keyword;
const page = parseInt(req.query.page || "0");
const PAGE_SIZE = 20;
const query = new RegExp(data, "i");
const total = await Post.countDocuments({});
const posts = await Post.find({ $or: [{ title: query }, { content: query }] })
.limit(PAGE_SIZE)
.skip(PAGE_SIZE * page);
if (!posts) {
return next(new ErrorHandlng("No posts were found", 400));
}
res.status(200).json({
status: "success",
data: {
totalPages: Math.ceil(total / PAGE_SIZE),
posts,
},
});
});
My api class(front end,copied only the calling for that specific get request):
import axios from "axios";
const baseURL = "http://localhost:8000";
axios.defaults.withCredentials = true;
const API = axios.create({
baseURL,
credentials: "include",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});
export const getPostsByKeyword = (keyword, page) =>
API.get(`/post/getPostsByKey?page=${page}`, keyword);
Post slice class:
export const fetchPostsByKeyWord = createAsyncThunk(
"post/getKeyword",
async ({ keyword, page }, { fulfillWithValue, rejectWithValue }) => {
try {
const response = await api.getPostsByKeyword(keyword, page);
if (response.statusCode === "400") {
throw new Error("There are no available posts");
}
const fetchData = await response.data.data.posts;
const totalPages = await response.data.data.totalPages;
return fulfillWithValue({ fetchData, totalPages });
} catch (err) {
console.log(err.response.message);
}
}
);
const initialState = { status: "undefined" };
const PostSlice = createSlice({
name: "post",
initialState,
reducers: {},
extraReducers: {},
});
export const postActions = PostSlice.actions;
export default PostSlice;
Calling the backend:
dispatch(fetchPostsByKeyWord({ keyword, page }))
.unwrap()
.then((originalPromiseResults) => {
console.log("thte " + " " + originalPromiseResults.totalPages);
console.log("The data is" + originalPromiseResults.fetchData);
setTotalPages(originalPromiseResults.totalPages);
})
.catch((err) => {
console.log(err.message);
});
As you can see I have not copied the whole code, I copied only the parts that are relevants for the question.
Browsers cannot currently send GET requests with a request body. XMLHttpRequest (which Axios uses) will ignore it and fetch() will trigger an error.
See also HTTP GET with request body for extra discussion on why trying this might be a bad idea.
You should instead pass everything required in the query string, preferably via the params option so it is correctly encoded...
export const getPostsByKeyword = (keyword, page) =>
API.get("/post/getPostsByKey", { params: { page, keyword } });
and grab the data via req.query server-side.
const { page, keyword } = req.query;
With vanilla JS, you can use URLSearchParams to construct the query string...
const params = new URLSearchParams({ page, keyword });
// XHR
const xhr = new XMLHttpRequest();
xhr.open("GET", `/post/getPostsByKey?${params}`);
// Fetch
fetch(`/post/getPostsByKey?${params}`); // GET is the default method
Your Axios instance creation could also be a lot simpler...
Axios is usually quite good at setting the correct content-type header, you don't have to
Your Express app isn't doing any content-negotiation so you don't need to set the accept header
Unless you're actually using cookies (which it doesn't look like), you don't need credential support
const API = axios.create({ baseURL });

How to pass data in slug.js Reactjs

I am new in Nextjs, i am trying to integrate [slug.js] page, i want to know that how can we manage/get data in sidebar (similar blogs) ? in other words for blog details i used "get static path" and "props", But now i want to pass "current slug" ( to API) so i can fetch all blogs with this blog category,How can i do this ?
Client-side approach:
Since you pass the post as page-props via getStaticProps, you can either take the slug from there (if it's included in your data model), or extract the slug from the url via next's useRouter hook in case you want to do client-side fetching:
import axios from "axios"; // using axios as an example
import { useRouter } from "next/router";
const Component = () => {
const [similarPosts, setSimilarPosts] = useState([]);
const router = useRouter();
const { slug } = router.query;
const getSimilarPosts = async () => {
if (!router.isReady() || !slug) return [];
const { data } = await axios.get("/api/similar-posts-route/" + slug);
return data;
};
useEffect(() => {
if (similarPosts.length > 0) return;
(async () => {
const posts = await getSimilarPosts(); // assuming API returns an array of posts as data.
setSimilarPosts(posts);
})();
}, []);
return <div>Similar posts: {JSON.stringify(similarPosts)}</div>;
};
[...]
Server-Side approach (preferred):
I believe it would be a better approach to directly fetch similar posts inside getStaticProps to reduce API calls and for a better UX.
Inside getStaticProps you can take the slug from context.params and fetch all similar posts directly from your database/CMS, and pass them directly as props to your page component:
export async function getStaticProps({ params }) {
const { slug } = params;
// fetch similar posts directly from the database using the slug (don't call the API, it's not up yet during build phase)
const similarPosts = await executeDatabaseQueryForSimilarPosts(slug);
// [...] fetch the rest of the page props
return {
props: {
similarPosts,
// [...] return the rest of page props
},
revalidate: 60 * 30 // re-fetch the data at most every 30 minutes, so the posts stay up to date
};
}
// directly take all similar posts from props
const Component = ({similarPosts}) => {
return <div>Similar posts: {JSON.stringify(similarPosts)}</div>;
};

How to identify an element in a table whatever its place

Here is the new script with the find function which allows me to identify a single element of the array for sure but there is still a small problem. As you can see it's my const crypto which contains the data I want to display on the front end. However when I want to call crypto at the return level the const is not recognized.
Hello again,
I updated the script now it works I can display on the front end the data I want however I have the impression that the request to the api is executed several times when I would like there to be only one request
I put below a screen of the console.log of my script.
As you can see the data requested is displayed first as undefined then it is displayed several times, then I put blocked due to the too large number of requests made in little time
Thanks for your help
How do I make my requests :
import { useState, useEffect } from "react";
function App() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null)
useEffect(() => {
fetch("http://localhost:4500/coingeckotest")
.then(response => {
if (response.ok) {
return response.json()
}
throw response;
})
.then(data => {
setData(data)
})
.catch(error => {
console.error("Error fetching data: ", error)
setError(error)
})
.finally(() => {
setLoading(false)
})
}, [])
const uniswap = data&&data[0].tickers?.find(donne =>
donne.trade_url === 'https://app.uniswap.org/#/swap?
inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c599&
outputCurrency=ETH')
const uniprice = uniswap?.converted_last?.usd
const sushiswap = data&&data[1].tickers?.find(donne =>
donne.trade_url === 'https://app.sushi.com/swap?
inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c59
9&outputCurrency=ETH')
const sushiprice = sushiswap?.converted_last?.usd
const curvefinance = data&&data[2].tickers?.find(donne =>
donne.base === 'DAI')
const curveprice = curvefinance?.converted_last?.usd
const quickswap = data&&data[3].tickers?.find(donne =>
donne.trade_url === 'https://quickswap.exchange/#/swap?
inputCurrency=0x0d500b1d8e8ef31e21c99d1db9a6444d3adf127
0&outputCurrency=0xbbba073c31bf03b8acf7c28ef0738decf369
5683')
const quickprice = quickswap?.converted_last?.usd
console.log(uniprice)
console.log(sushiprice)
console.log(curveprice)
console.log(quickprice)
if (loading) return "Loading..."
if(error) return "Error !"
return (
<>
</>
)
}
export default App;
Thank you in advance for your answers
You can use the Array.find method to find out the first entry that matches a particular coin_id. The code for that would be:
const desiredCoinID = "something"; (determined by some user input)
const desiredCoinObject = data.find(coin => coin.coin_id === desiredCoinID);
const priceInUSD = desiredCoinObject?.tickers?.converted_last?.usd;
——-Updated Answer——-
Hi, this is my answer to your updated question. const crypto that you use is available only within the scope of the callback of the useEffect function, which is why you cannot see the results on your screen. There are two ways you can go about it:
First, you can declare crypto as a let outside the useEffect and then update it inside your useEffect. That way your crypto will have global scope. But there is a better way to do this, which is to use the useState hook.
You can declare a crypto, setCrypto using useState and then use the setter to update the value if crypto inside useEffect after the data fetching is over. Let me know if you need help writing code.

How can I use "useRouter" to get params in the url inside getServerSideProps() in Next.js [duplicate]

This question already has answers here:
How to access query params inside getServerSideProps in Next.js?
(2 answers)
Closed 10 months ago.
I want to get the URL params in the getServerSideProps() function. Here's my code.
The purpose of my code is to take the params from the URL and fetch the API and display the output on the frontend.
import { useRouter } from 'next/router'
import connectMongo from '../../utils/connectMongoos';
import Post from '../../models/postModel';
import MarkdownComponent from '../../components/utils/markdown';
export const getServerSideProps = async () => {
try {
console.log('CONNECTING TO MONGO');
await connectMongo();
console.log('CONNECTED TO MONGO');
console.log('FETCHING DOCUMENTS');
// find the post with the slug that matches the slug in the url
const post = await Post.findOne({ slug: router.query.slug }); // error comes here
console.log('FETCHED DOCUMENTS');
return {
props: {
data: JSON.parse(JSON.stringify(post)),
},
};
} catch (error) {
console.log(error);
return {
notFound: true,
};
}
};
export default function Posts({data}) {
const router = useRouter()
// const { slug } = router.query
return(
<div className="max-w-screen-md mx-auto font-inter m-2 p-4">
<MarkdownComponent text={data.markdown} />
</div>
)
}
Here's the error that I am encountering,
ReferenceError: router is not defined
at getServerSideProps (webpack-internal:///./pages/post/[slug].js:26:19)
at runMicrotasks (<anonymous>)
As per the NextJs getServerSideProps Documentation, you can access the route parameters through the getServerSideProps's context, using the params field.
params: If this page uses a dynamic route, params contains the route parameters. If the page name is [id].js , then params will look like { id: ... }.
query: An object representing the query string.
export async function getServerSideProps(context) {
const slug = context.params // `Get the router query or slug here`
// Rest of `getServerSideProps` code
}

Refresh tokens with axios Interceptors + React + Redux

In my application, I m using React with Redux and axios.
I am trying to refresh my JWT token if needed via axios interceptors.
I am able to intercept the requests, check if my access token is valid, and if it is expired I am able to request a new pair of tokens using my refresh token.
However, after I obtain my new access and refresh token, my app does not continue with the original request, but it stops and tries to render my components with errors (given that I am missing the response from the original request).
I believe there is some error in how I manage my async functions
I configured an axios instance as follows
in axiosHelper.js
import axios from 'axios';
import jwt_decode from "jwt-decode"
import dayjs from 'dayjs'
let authTokens = localStorage.getItem('authTokens') ? JSON.parse(localStorage.getItem('authTokens')) : null
const instance = axios.create({ baseURL: 'http://localhost:8000'});
instance.interceptors.request.use(async (req) => {
if(!authTokens){
authTokens = localStorage.getItem('authTokens') ?
JSON.parse(localStorage.getItem('authTokens')) : null
}
const user = jwt_decode(authTokens.access)
const isExpired = dayjs.unix(user.exp).diff(dayjs()) < 1
if (!isExpired) return req
const {tokens} = await axios.post(`/refresh-url/`, {
refresh: authTokens.refresh
})
console.log('refreshed1')
const data = authTokens
data.refresh = tokens.refresh
data.access = tokens.access
console.log('refreshed2')
localStorage.setItem('authTokens',JSON.stringify(data))
req.headers.Authorization = `Bearer ${tokens.access}`
console.log('refreshed3')
return req
}, error => {
return Promise.reject(error);
});
export default instance;
In my actions I import the instance as in this example
in actions.js
import axios from '../axiosHelper.js '
...(here my imports and actions)...
const action = async () =>{
const config = { headers: {
'Content-type': 'application/json',
Authorization: `Bearer ${token.access}` // token from the redux store
}
const { data } = await axios.get(
`/api/my-url/`,
config
)
...(send data to reducer)...
}
then in my components, I call my actions via dispatch in useEffect.
in Home.js
const Home = (props) => {
const dispatch = useDispatch()
useEffect(() =>{
dispatch(action())
}, [dispatch])
return (<my component/>)
}
I believe the problem has something to do with dispatch. If the access token is valid, then everything works fine. However, if it is expired, my interceptor will send the request to refresh the tokens (which is successful), but as soon as the tokens are returned, my component tries to render and the rest of the code in the axios interceptor is ignored (I checked this with console log ...), and the original request is not sent (I checked that it does not arrive at my backend server).
I would really appreciate some help as I cannot figure out hoe to solve the problem!
I solved the issue by importing the redux store into my axiosHelper.js script, and then using store.dispatch(refreshaction(authTokens.refresh)) inside my axios interceptor.

Categories