Working on my first project and need some help. I succeeded with React to use Spotify API to fetch my playlists. Now I want to build a search component, but I am getting a 401 returned. I assume that the problem is in my headers (Content-Type??).
import React, {useEffect, useState} from "react";
import axios from "axios";
import {useOptionContext} from "../context/SelectedOptionsProvider";
export default function ArtistOnSpotify() {
const [token, setToken] = useState("");
const [data, setData] = useState({});
const {
selectedArtist,
} = useOptionContext();
console.log("localstorage", localStorage);
console.log("token", token);
useEffect(() => {
if (localStorage.getItem("accessToken")) {
console.log(localStorage);
setToken(localStorage.getItem("accessToken"));
}
}, []);
async function ArtistOnSpotify() {
try {
console.log(token);
const response = await axios.get(`https://api.spotify.com/v1/search?query=${selectedArtist}`, {
headers: {
Authorization: "Bearer " + token,
Accept: "application/json",
"Content-Type" : "application/json",
// Content-Type : "application/json",
},
})
;
console.log(response.data);
// setData(response.data);
} catch (error) {
console.log(error);
}
;
};
return (
<div>
<button onClick={() => ArtistOnSpotify()}>klik</button>
</div>
)
}
Related
I've been working on this for hours, and I have no idea where did it go wrong.
I want to have an axios interceptor for my ReactJs
this is my interceptor axiosHandler.js
import axios from "axios";
const axiosHandler = axios.create({
baseURL: process.env.REACT_APP_BASE_URL,
headers: {
Accept: "application/json",
},
});
axiosHandler.interceptors.request.use(
(config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers["Authorization"] = "Bearer " + token;
}
return config;
},
(error) => {
Promise.reject(error);
}
);
//axiosHandler.interceptors.response
export default axiosHandler;
And here is how I use the handler in my other component
import axiosHandler from "../services/axiosHandler";
const getData = async () => {
await axiosHandler
.get(`/path`)
.then((response) => {
//do something
})
};
And I get an error of below
services_axiosHandler__WEBPACK_IMPORTED_MODULE_0_.get is not a function
I've read many other solutions, but I can't find the difference as how it leads to the error of mine.
Where do I put it wrong?
Thank you
inside axios.index
import axios from "axios";
import { API_URL } from "../config/config";
const axiosHttp = axios.create({
baseURL: `${API_URL}`,
});
axiosHttp.interceptors.request.use(
(config) => {
const token = "Your Token here"
return {
...config,
headers: {
...(token !== null && { Authorization: `${token}` }),
...config.headers,
},
};
},
(error) => {
return Promise.reject(error);
}
);
axiosHttp.interceptors.response.use(
(response) => {
//const url = response.config.url;
//setLocalStorageToken(token);
return response;
},
(error) => {
if (error.response.status === 401) {
//(`unauthorized :)`);
//localStorage.removeItem("persist:root");
//removeLocalStorageToken
//window.location.href = "/login";
}
return Promise.reject(error);
}
);
export default axiosHttp;
Then inside your API function use it like below
import axiosHttp from "./utils/axios";
const getData = async ()=>{
try{
const response = await axiosHttp.get('/path')
return resposne;
}
catch(error){
//handle error here...
}
}
Last but not least, you shouldn't use await when using callback (then/catch)
I am using axios to hit an API to upload a .apk file onto a 3rd party app which is running locally on my computer. Using the API on Postman is giving the desired result but while integrating it with my React app I am getting POST http://localhost:8000/api/v1/upload 400 (Bad Request) error.
I have the following with structure:
src/httpRequest.js
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8000",
headers: {
"Content-type": "application/json",
Authorization: <API_KEY>
}
});
src/services/Upload.js
import http from "../httpRequest";
const upload = (file, onUploadProgress) => {
const formData = new FormData();
formData.append("file", file);
return http.post("/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
Authorization:
<API_KEY>
},
onUploadProgress,
});
};
export default {
upload,
};
src/components/ApkUpload.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const ApkUpload = () => {
const [selectedFiles, setSelectedFiles] = useState(undefined);
// eslint-disable-next-line no-unused-vars
const [currentFile, setCurrentFile] = useState(undefined);
const [progress, setProgress] = useState(0);
const [message, setMessage] = useState('');
const [fileDetails, setFileDetails] = useState([]);
const handleUpload = async () => {
const data = new FormData();
data.append('file', selectedFiles);
try {
const res = await axios.post('http://localhost:8000/api/v1/upload', data, {
headers: {
'Content-Type': 'multipart/form-data',
Authorization: <API_KEY>,
},
onUploadProgress: (progressEvent) => {
setProgress(parseInt(Math.round((progressEvent.loaded * 100) / progressEvent.total), 10));
},
});
} catch (err) {
if (err.response.status === 500) {
setMessage('There was a problem with the server');
} else {
setMessage(err.response.data.message);
}
}
};
const handleChange = (e) => {
setSelectedFiles(e.target.files);
setCurrentFile(e.target.files[0]);
};
useEffect(() => {
axios.get("http://localhost:8000/api/v1/scans", {
headers: {
Authorization:
<API_KEY>,
},
}).then(res => {
setFileDetails(res.data.content);
});
},[]);
return (
<div className="container">
// simple button calling above methods
</div>
);
};
export default ApkUpload;
I am using MobSF as my third party app and for upload they require multipart/form-data.
While using postman I was able to get the desired result but I'm not able to do so with my frontend. Any help regarding this issue will be highly appreciated!
const data = new FormData();
data.append('file', selectedFiles[0]);
Inside your handleUpload function selectedFiles state is of type FileList but it should be File.
If you are handling single file then you can use:
data.append('file', selectedFiles[0]);
For multiple files you can do:
for(let i=0;i<selectedFiles.length;++i){
data.append('file',selectedFiles[i])
}
I am trying to pass token that comes from Redux store in an axios instance(useRequest). I want to pass the token while I am calling the instance
requestMethod.js
import axios from "axios";
const BASE_URL = "http://localhost:5000/e-mart/";
//Declaring a function to pass the Token dynamically.
export const userRequest =(TOKEN) => axios.create({
baseURL: BASE_URL,
header: { token: `Bearer ${TOKEN}` }, // Here the token comes dynamically
});
Products.js
import { userRequest} from "../requestMethods";
import { useDispatch, useSelector } from "react-redux";
const {accessToken} = useSelector((state) => state.user.currentUser);//accessing token from redux store
useEffect(() => {
const abortController = new AbortController();
const getProdcuts = async () => {
try {
const res = await publicRequest.get(
`products`,
{ signal: abortController.signal } // Here is where i want to pass the token from redux stroe
);
setProducts(res.data);
} catch (err) {
console.log(err.message);
}
};
getProdcuts();
return () => {
abortController.abort();
};
}, []);
If token is dynamic, don't pass it while create axios instance
// Axios instance
export const userRequest =(TOKEN) => axios.create({
baseURL: BASE_URL
})
// how to call with different dynamic tokens
await API.patch('products',
{ signal: abortController.signal },
{
headers: {
token: `Bearer ${TOKEN}`,
},
},
);
I am try to fetch users information using github API
import React, { useEffect } from "react";
function UserResults() {
useEffect(() => {
fetchUsers();
}, []);
const fetchUsers = async () => {
const response = await fetch(`${process.env.REACT_APP_GITHUB_URL}/users`, {
headers: {
Authorization: `token ${process.env.REACT_APP_GITHUB_TOKEN}`,
},
});
const data = response.json();
};
return <div>Hello</div>;
}
export default UserResults;
And here is what I put in my env:
REACT_APP_GITHUB_TOKEN="<token>"
REACT_APP_GITHUB_URL = "https://api.github.com"
I am sure the token is correctly generated and copied.
But it seems I can't fetch the data due to some "JSON" error as it shows in the console like this.
Can anyone offers any help with this?
You need to await response.json() and update your header request
import React, { useEffect } from "react";
function UserResults() {
useEffect(() => {
fetchUsers();
}, []);
const fetchUsers = async () => {
const response = await fetch(`${process.env.REACT_APP_GITHUB_URL}/users`, {
headers: {
'Authorization': `token ${process.env.REACT_APP_GITHUB_TOKEN}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
});
const data = await response.json();
};
return <div>Hello</div>;
}
export default UserResults;
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 9 months ago.
I am new to React and am having a difficult time figuring out how I can wait for the state to have a specific (not null) update before fetching data. I am using firebase JWT and am passing the token into the headers but with my current code it runs and passed the value of null. Is there a nifty hook trick to ensure that my fetchData function only runs once and that it only runs after the token value is set?
I tried setting the state as const [token, setToken] = useState(auth.currentUser.getIdToken()); but it appears to return a promise into the header and not the token (guessing its because its async). Thanks!
import React, { useState, useEffect } from 'react';
import { auth } from '../../firebase-config';
const RecordEntry = (props) => {
const [token, setToken] = useState();
const [isLoading, setIsLoading] = useState(false);
var mydata =
{
entry_id = props.entry_id
}
//should only call this once
const fetchData = async () => {
const current_token = auth.currentUser.getIdToken();
setToken(current_token);
//need to yield here to verify token is set and not null - this is where I am stuck
fetch('https://mysite/api/recordEntry' , {
method: 'POST',
headers: new Headers({
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
}),
body: JSON.stringify(mydata)
})
.then((response) => response.json())
.then((data) => {
setIsLoading(false);
})
.catch((error) => {
setIsLoading(false);
console.log(error);
});
};
//passing empty array so the effect only runs once
useEffect(() => {
fetchData();
}, []);
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
<h1> Entry Recorded </h1>
</div>
);
};
export default RecordEntry;
Try this solution
const [didFetch,setDidFetch] = useState(false)
useEffect(() => {
if(!didFetch){
setDidFetch(true)
fetchData();
}
}, []);
"Thanks for the response, I attempted this solution but the token is still not updated. The header shows it's a promise object, instead of the expected token string. The token is still awaiting to update essentially. I need a method that pauses the data fetch until the token is filled."
So try this:
const [token, setToken] = useState(null);
And
useEffect(() => {
if (token != null) fetchData();
}, [token]);
Using #awolf's suggestion of await for current_token and then bass that as the auth bearer instead of the version updating to state. Worked perrfectly. Here is the final solution:
import React, { useState, useEffect } from 'react';
import { auth } from '../../firebase-config';
const RecordEntry = (props) => {
const [token, setToken] = useState();
const [isLoading, setIsLoading] = useState(false);
var mydata =
{
entry_id = props.entry_id
}
//should only call this once
const fetchData = async () => {
const current_token = await auth.currentUser.getIdToken();
setToken(current_token);
//need to yield here to verify token is set and not null - this is where I am stuck
fetch('https://mysite/api/recordEntry' , {
method: 'POST',
headers: new Headers({
"Content-Type": "application/json",
Authorization: `Bearer ${current_token}`,
}),
body: JSON.stringify(mydata)
})
.then((response) => response.json())
.then((data) => {
setIsLoading(false);
})
.catch((error) => {
setIsLoading(false);
console.log(error);
});
};
//passing empty array so the effect only runs once
useEffect(() => {
fetchData();
}, []);
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
<h1> Entry Recorded </h1>
</div>
);
};
export default RecordEntry;