I'm going to use Axios to communicate API.
But that kind of error keeps coming out. I don't understand this problem. I searched on the Internet and tried everything. Help me.
All I want is to click on that button to see the low value in the developer tool.
useEffect(() => {
setJwt(getClientCookieFromClient('jwt'));
}, []);
const customFetch = async () => {
const res = await axios
.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
})
.then((res) => res.data);
if (!res.data.success) {
alert(res.data.message);
}
};
...
<button onClick={() => customFetch()}>API호출버튼</button>
Alway wrap await inside try/catch block.
const customFetch = async () => {
try {
const res = await axios
.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
})
.then((res) => res.data);
if (!res.data.success) {
alert(res.data.message);
}
} catch (error) {
console.log(error);
// Do something with error
}
};
Try
useEffect(() => {
setJwt(getClientCookieFromClient('jwt'));
}, []);
const customFetch = async () => {
const res = await axios.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
});
if (!res.data.success) {
alert(res.data.message);
}
};
Note:
not sure about you response structure. Current code works as expected for structure:
res = { data: { data: {success: true}}}
if it is not so, then use if statement as !res.success
useEffect(() => {
setJwt(getClientCookieFromClient('jwt'));
}, []);
const customFetch = async () => {
const res = await axios
.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
})
.then((res) => res.data)
.catch((err) => console.log("Error while fetching",err)); //<--- use .catch for catching error
if (!res.data.success) {
alert(res.data.message);
}
};
Related
POSTING API
export const resendInvitation = async (userName) => { await API.post( 'delta-api',user-mgmt/users/${userName}/resendInvitation, {} ); };
const handleResendInvitation = async () => { await resendInvitation(userName) .then((response) => { setOpen(false); }) .catch((e) => { setOpenNotification(true); setNotificationMessage(e.response.data.message); }); };
help me to get the response data
I'm getting some data from server and have set-up this service on client to request them accordingly:
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
const { data } = await axios.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
return data
}
service is called within context:
const syncFollowedArtists = async () => {
await spotifyService
.serviceSyncFollowedArtists(user.userId)
.then(res => {
if (res.length === 0) return
dispatch({
type: 'SYNC',
data: res,
})
})
.catch(err => {
console.log(err)
})
}
It works fine as I want it to, however, before, I have set up the service to request data using promises:
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
await axios
.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
.then(res => {
return res.data
})
.catch(err => {
console.log(err.message)
})
}
Even though I manage to obtain the data from server inside the service, when it's returned to the function in context, it's empty, undefined. Is threre any reason for this?
You are getting undefined because you are not returning anything from the function in the case of promises, unlike you are doing it in the first case
So just add a return keyword
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
return await axios
.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
.then(res => {
return res.data
})
.catch(err => {
console.log(err.message)
})
}
So, I'm trying to run a asynchronous function inside of the functional component in React (NextJS). But no matter what I do, the function just returns a pending promise like this: Promise {<pending>}. I tried fetching the data from a dummy API, and it works as its supposed to.
The thing is that for this particular case, I need to grab the access_token from the getServerSideProps, which is probably the reason why I am facing these problems (I might be wrong though).
It's worth noting that using a console.log inside of the function, instead of the standard return, gives the correct result.
const checkLoved = async (id: string) => {
try {
const response = await fetch(`https://api.spotify.com/v1/me/tracks/contains/?ids=${id}`, {
headers: {
Authorization: `Bearer ${test.access_token}`,
},
});
const data = await response.json();
return data[0];
} catch (error) {
console.error(error);
}
};
export async function getServerSideProps(context) {
const session = await getSession(context);
if (!session) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
const {
token: { accessToken },
} = session;
const test = await getAccessToken(accessToken);
return {
props: { test, accessToken },
};
}
Additonal info
What I'm trying to achieve:
const Discover: NextPageWithLayout = ({ test }: IDiscover) => {
const checkLoved = async (id: string) => {
try {
const response = await fetch(`https://api.spotify.com/v1/me/tracks/contains/?ids=${id}`, {
headers: {
Authorization: `Bearer ${test.access_token}`,
},
});
const data = await response.json();
return data[0];
} catch (error) {
console.error(error);
}
};
const array = [{ test: 1 }, { test: 2 }];
return (
<div>
{array.map((item) => {
console.log();
return <Component test={checkLoved('7jCy1opEtV4a0TnKrtsSdo')}>{item.test}</Component>;
})}
</div>
);
};
Fixed it by creating a custom hook.
const useLoved = (id, access_token) => {
const [loved, setLoved] = useState(null);
useEffect(() => {
const isLoved = async () => {
const response = await fetch(`https://api.spotify.com/v1/me/tracks/contains/?ids=${id}`, {
headers: {
Authorization: `Bearer ${access_token}`,
},
});
const data = await response.json();
setLoved(data[0]);
};
isLoved();
});
return loved;
};
Then you just need to call it:
const loved = useLoved('7jCy1opEtV4a0TnKrtsSdo', test.access_token);
I'm using a react frontend and fetching data from my node server. I feel like my code looks a bit redundant, is there a better way to refactor all this?
App.js
searchStock = async (value) => {
let priceURL = `/stock/${ value }/price`
// fetch price data
fetch(priceURL)
.then(res => {
if (res.ok) {
res.json()
.then( (result) => {
this.setState({
price: result
})
})
}
else {
console.log("Something went wrong...")
}
})
}
server.js
app.get('/stock/:symbol/price', (req, res) => {
const token = 'abcde123'
const symbol = req.params.symbol
const apiURL = `https://sandbox.iexapis.com/stable/stock/${symbol}/price?token=T${token}`
fetch(apiURL)
.then(response => {
console.log(response.status)
if (response.ok) {
response.json().then((data) => {
res.json(data)
});
}
else {
res.sendStatus(response.status)
}
})
.catch(error => {
console.log(error);
});
})
As these two code segments live in different apps (frontend and backend) I don't think there's a pretty way of DRYing this.
Introduce library file with fetching logic
src/helper.js
exports.fetchHelper = (url) => fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
res.sendStatus(response.status)
}
})
.catch(console.error);
and use respectively
app.js
import { fetchHelper } from 'src/helper'; // or whatever else your bundler setup requires
searchStock = async (value) => {
const priceURL = `/stock/${ value }/price`;
await fetchHelper(priceURL).then((result) => {
this.setState({
price: result
})
})
}
server.js
const fetchHelper = require('src/helper').fetchHelper;
app.get('/stock/:symbol/price', (req, res) => {
const token = 'abcde123'
const symbol = req.params.symbol
const apiURL = `https://sandbox.iexapis.com/stable/stock/${symbol}/price?token=T${token}`
fetchHelper(apiURL).then((response) => {
res.json(data);
})
Or something similar...
I am trying to test the loadAllProjects function.
The test fails at .then() with the error: TypeError: Cannot read property 'then' of undefined
I have also tried mocking the reponse of getHeadersWithToken() but could not get it to work.
Snookered on this one and would appreciate any help.
test:
it('should create SET_ALL_PROJECTS action when fetching projects', () => {
fetch
.once(JSON.stringify([{ access_token: "12345" }]))
.once(JSON.stringify({ name: "x" }))
const expectedActions = [
{ type: "SET_ALL_PROJECTS", json: { name: "x" } },
]
store.dispatch(actions.loadAllProjects.apply())
.then(() => { // FAILS HERE
expect(store.getActions()).toEqual(expectedActions)
})
});
code:
export const getHeadersWithToken = () => {
return fetch("/.auth/me", requestOptions)
.then(parseResponseAndHandleErrors)
.then(json => {
const header = 'Bearer ' + json[0].access_token
const applicationJsonHeaders = getJsonHeaders(header)
return applicationJsonHeaders
})
.catch( error=> {
console.error(error)
})
}
export const loadAllProjects = () => {
return (dispatch) => {
getHeadersWithToken()
.then(applicationJsonHeaders => {
const requestOptions = {
method: 'GET',
headers: applicationJsonHeaders,
};
return fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
.then(parseResponseAndHandleErrors)
.then(json => {
dispatch(setAllProjects(json))})
.catch(error => {
console.error(error)
dispatch(failedToLoadProjects(error))
});
})
}
}
store used in test:
const store = mockStore(Map(
{
allProjects: Map({
}),
currentProject: Map({
authenticationData: Map({
})
})
})
);
What Redux middleware are you using for the async stuff? Make sure you set up the middleware when creating the store for testing.
Since i dont see that anywhere in your code above im gonna assume we are not using that middleware here.
Since loadAllProjects is a higher order function i would do this:
it('should create SET_ALL_PROJECTS action when fetching projects', (done) => {
fetch
.once(JSON.stringify([{ access_token: "12345" }]))
.once(JSON.stringify({ name: "x" }))
const expectedActions = [
{ type: "SET_ALL_PROJECTS", json: { name: "x" } },
]
// Higher order function that returns a new function.
const loadAllProjectsAsync = actions.loadAllProjects();
// The function returned expects a dispatch from Redux as an argument.
// It will do async work and when its done, it will call the provided dispatch.
loadAllProjectsAsync(store.dispatch).then(() => {
expect(store.getActions()).toEqual(expectedActions);
done();
})
});
You also need to modify your code for loadAllProjects so that the inner function returns the promise:
export const loadAllProjects = () => {
return (dispatch) => {
// You will need to return the promise in order for the test to be able to call .then() on it.
return getHeadersWithToken()
.then(applicationJsonHeaders => {
const requestOptions = {
method: 'GET',
headers: applicationJsonHeaders,
};
return fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
.then(parseResponseAndHandleErrors)
.then(json => {
dispatch(setAllProjects(json))})
.catch(error => {
console.error(error)
dispatch(failedToLoadProjects(error))
});
})
}}
Also, as already stated, you must tell the jest when the test is done if you are testing async stuff. Do this by letting your it call take done as a param and call that as a function after you have verified the outcome i the .then()
This was just a quick fix from my side. There still might be something im missing or some bugs in the code above, but you get the point.
Let me know if you have any follow up questions?
In case this is ever useful to anyone and in acknowledgment of Septastium's answer, I eventually changed the code to:
async getHeadersWithToken(requestType) {
if (process.env.REACT_APP_RUNNING_LOCALLY==="true") {
return {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
};
}
let result = await fetch("/.auth/me", this.requestOptions)
let headers = result.json()
.then( json => {
const header = 'Bearer ' + json[0].access_token
const applicationJsonHeaders = this.getJsonHeaders(header, requestType)
return applicationJsonHeaders
})
.catch(error => {
console.error(error)
})
return headers
}
export const loadAllProjects = () => {
return async dispatch => {
const authenticator = new Authenticator()
let applicationJsonHeaders = await authenticator.getHeadersWithToken(constants.GET)
let loggedInUser = await authenticator.getLoggedInUser()
const requestOptions = {
method: 'GET',
headers: applicationJsonHeaders,
};
return await fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
.then(response => {
return parseResponseAndHandleErrors(response)
})
.then(json => dispatch(setAllProjects(json)))
.then(()=> dispatch(setAuthenticationData(loggedInUser)))
.catch(error => {
console.error(error)
return dispatch(failedToLoadProjects(error))
});
}
}
and the test to:
const checkActionsWereDispatched = async (expectedActions, actionCreator) => {
const store = mockStore(Map(
{
}),
);
store.dispatch(await actionCreator.apply()).then(() => {
expect(store.getActions()).toEqual(expectedActions)
})
}
it('should create SET_ALL_PROJECTS action when fetching projects', async () => {
fetch
.once(JSON.stringify([{ access_token: "12345" }]))
.once(JSON.stringify({ name: "x" }))
const expectedActions = [
{ type: "SET_ALL_PROJECTS", json: { name: "x" } },
]
checkActionsWereDispatched(expectedActions, actions.loadAllProjects)
});
As noted above I think Spetastium's version of the test is easier to read than mine and his article here was very helpful.