Parse Nested JSON Using Axios and Async/Await - reactjs

I am trying to fetch data from an api which should return a json object with an array of recipes. I am using React hooks on the front end and Axios to perform the request. The hook runs but I get an error while trying to access the json array from the response.
Here's the sample api response:
{
count: 30,
recipes: [objects, ... 29]
}
and my code to get the recipe response:
const fetchRecipes = async () => {
try {
const recipeData = await Axios.get(api);
console.log(recipeData);
const recipes = await recipeData.json(); // error occurs here
setRecipes(recipes);
setLoading(false);
} catch (err) {
console.log(`Error occurred fetching recipes ${err}`)
}
};
useEffect(() => {
fetchRecipes();
}, []);
I have removed the hooks declarations and api url is https://api.myjson.com/bins/t7szj. The problem lies in getting the array from the response. Is there something wrong with my api call?
This is the error message:
Error occurred fetching recipes TypeError: recipeData.json is not a function

Did you try this?
const fetchRecipes = async () => {
try {
const recipeData = await Axios.get(api);
console.log(recipeData.data);
const recipes = recipeData.data;
setRecipes(recipes);
setLoading(false);
} catch (err) {
console.log(`Error occurred fetching recipes ${err}`)
}
};
you don't have to call res.json() on the response when using axios (unlike fetch) because axios handles that for you automatically. Meaning that axios parses the response to JSON by default.
async/await with Axios

Related

res.json not working correctly with axios / React

What I want to do :
I send the GET request through axios
I open a local Json file with fs.readfile
I process the data and return it
I want to display the data when it return with res.json
what actually happened
I send the GET request through axios
I open a local Json file with fs.readfile
They return the data before fs.readfile finished so it's undefined or blank
This one I put on the frontend and the controller
//frontend
const fetchRewards = async()=>{
let link ="/api/reward";
const {data} = await axios.get(link);
console.log(data); **// this one logging undefined**
}
// on controller
async getRewardsById(req,res,next) {
try {
const result = await rewardService.getReward();
res.json(result);
} catch (error) {
next(error);
}
},
This is my service
const getReward = async () => {
fs.readFile("test.json", (err, inputData) => {
return {"name":"John", "age":30, "car":null};
}
console.log("done");
}
Seems to me like you are not returning anything from your service?
Try returning the fs.readFile.

Receiving undefined instead of JSON

I am using React axios to receive the JSON (array of objects) from server (server side is written on Go, I checked via Postman, JSON is sent properly).
Here is how I get the data on client side:
export const getPostData = async () => {
const URL = 'http://localhost:8083/test'
try {
const { data: { data }} = await axios.get(URL);
console.log(data)
return data;
} catch (error) {
console.log(error)
}
};
And this is how the getPostData is called in App.js:
const App = () => {
const [ posts, setPosts ] = useState([]);
useEffect(() => {
getPostData()
.then((data) => {
setPosts(data)
console.log(data)
})
},[]);
The problem is I get undefined in browser console. I found many similar questions asked here, but I could not find the solution (the Access-Control-Allow-Origin header is set when I send the JSON).
What should I learn more, where could be the problem? I would be very grateful for any help!
If this could be helpful, here is how I send the JSON in Go:
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Content-Type", "application/json")
c.JSON(http.StatusOK, gin.H{
"message": "Hello",
})
This looks suspect:
const { data: { data }} = await axios.get(URL);
That tries to read a property called data from an object on the data property of the response from axios, like this without the destructuring:
const data = (await axios.get(URL)).data.data;
Your Go code doesn't look like it puts a {"data": ___} wrapper around what it sends, and Axios only adds one layer of {data: ___} wrapper to what it gives you in the response, not two.
If you want the object from the JSON response, remove the inner destructuring:
const { data } = await axios.get(URL);
data will be {message: "Hello"} assuming the Go code sends the JSON {"message": "Hello"}.
Separately, your JavaScript code seems to expect an array of posts, but your Go code is just sending {"message": "Hello"}.

React Query useQuery & Axios

I'm trying to create an API function with a help of React Query and Axios.
When I'm using useQuery with vanilla fetch function - it all works perfectly.
export const useGetDebts = async () => {
const { families } = appStore.user;
const res = useQuery("getDebts", async () => {
const res = await fetch(`${API_URL}/api/family/${families[0]}/debts`, {
method: "GET",
headers: {
Authorization: `Bearer ${appStore.token ?? ""}`,
},
});
const parsedBody: DebtsResponse = await res.json();
return parsedBody;
});
return res;
};
But when I switch the vanilla fetch function to Axios - I get an error status of 500 (not sure if it comes from React Query or Axios).
export const useGetDebts = async () => {
const { families } = appStore.user;
const res = useQuery("getDebts", async () => {
const res = await axiosInstance.get<DebtsResponse>(`/api/family/${families[0]}/debts`);
return res.data;
});
return res;
};
Thanks in advance for any explanations/suggestions.
P.s. The axiosInstance works fine with the useMutation hook. So it only makes me more confused. =(
export const useGetDebt = () => (
useMutation(async (id: number) => {
const { families } = appStore.user;
const res = await axiosInstance.get<DebtResponse>(`/api/family/${families[0]}/debts/${id}`);
return res.data;
})
);
P.s.s. I'm working with React Native if it's somehow relevant.
react-query doesn't give you any 500 errors because react-query doesn't do any data fetching. It just takes the promise returned from the queryFn and manages the async state for you.
I'm not sure if the fetch code really works because it doesn't handle any errors. fetch does not transform erroneous status codes like 4xx or 5xx to a failed promise like axios does. You need to check response.ok for that:
useQuery(['todos', todoId], async () => {
const response = await fetch('/todos/' + todoId)
if (!response.ok) {
throw new Error('Network response was not ok')
}
return response.json()
})
see Usage with fetch and other clients that do not throw by default.
So my best guess is that the fetch example also gives you a 500 error code, but you are not forwarding that error to react-query.

How to dispatch post data object using async thunk redux axios middleware

I am trying to dispatch a post of an object data using async redux axios middleware. I am getting 400 https response prob due to formatting. Here is what I have for my code. Any feedback is great!
import { createAsyncThunk } from '#reduxjs/toolkit';
import axios from 'axios';
export const postResults = createAsyncThunk(
'results/postResults',
async ({ data: TestData[] }) => {
const response = await axios.post(`${url}/data/results`, { data });
return response.data;
}
);
const sendData = async (data) => {
try {
data = {
result: 'passed',
data_id: [0]
};
await dispatch(postResults(data));
} catch (err) {
console.log(err);
}
};
I am using sendData(data) in another function to trigger the event.
const processData = (e) => {
//.....
sendData(data);
}
The output I am getting when I debug under xhr.js request.send(requestData):
requestData: "{\"data\":{\"result\":\"passed\",\"data_id\":[0]}}"
I think the formatting is an issue which I have tried to remove data so I can be read and sent its request as
requestData: "{\"result\":\"passed\",\"data_id\":[0]}"
Any thoughts or feedback!
figured out, I removed the { } so its like this:
const response = await axios.post(${url}/data/results, data);

React query mutation: getting the response from the server with onError callback when the API call fails

I am working on a React JS project. In my project, I am using React query, https://react-query.tanstack.com/docs/guides/mutations. I am using mutation to make the post request to the server. But I am trying the get the response returns from the server when the API call fails with the onError call back.
This is my code.
let [ createItem ] = useMutation(payload => createItem(payload), {
onSuccess: (response) => {
},
onError: (error) => {
// here I am trying to get the response. In axios, we can do something like error.data.server_error_code
},
onMutate: () => {
}
})
As you can see in the comment, I am trying to read a field returned from the server within the onError callback. How can I do that?
let [ createItem ] = useMutation(payload => createItem(payload), {
onSuccess: (response) => {
},
onError: (error) => {
console.log(error.response.data);
console.log(error.response.status);
},
onMutate: () => {
}
})
It's not entirely clear when just doing console.log(error) inside onError, but error.response should be available.
It should work as it is. Make sure that your HTTP client (probably, Axios) is configured to throw an error. For example:
import axios from 'axios'
import { useMutation } from 'react-query'
import { BASE_URL } from 'constants/api'
const client = axios.create({
baseURL: BASE_URL,
})
const request = (options) => {
const onSuccess = (response) => response
const onError = (error) => {
// Throwing an error here
throw error
}
return client(options).then(onSuccess).catch(onError)
}
const { mutate } = useMutation(
async (data) =>
await request({
url: '/someUrl',
method: 'post',
data
}),
{ onError: (e) => console.log(e) }
)
And of course, it's better to store your Axios settings within a separate file, and then just import the 'request' variable where mutations are using.
If you are using fetch, you have to know that fetch does not throw any error unless is a network problem (as read here)
My solution was just to change to axios (which throws error when 400 or 500), but if you still need to use fetch, you need to find a way to make it throw errors instead.
I think the issue with NOT having an error.response in the callback depends on how the API is failing. If you look at the react-query documentation it shows that most HTTP libs like axios will throw if there is a non 2xx response. However it's up to the underlying API function how it handles that.
For example axios https://axios-http.com/docs/handling_errors will return the response object if there is a response from the server. They will return the request if the call has timed out and return just a message if the previous two don't fit the error
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
However, if you're using the Fetch API you have handle this yourself. Taken straight from react-query's docs: https://react-query.tanstack.com/guides/query-functions#usage-with-fetch-and-other-clients-that-do-not-throw-by-default
useQuery(['todos', todoId], async () => {
const response = await fetch('/todos/' + todoId)
if (!response.ok) {
throw new Error('Network response was not ok')
}
return response.json()
})

Resources