React Query useQuery & Axios - reactjs

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.

Related

Handling axios errors in child components?

My React app has an api client component which handles axios calls to the back end. So, in the api component I have:
async function getData(path: string, params?: any) {
const object: AxiosRequestConfig = {
...obj,
method: 'GET',
headers: {
...obj.headers,
},
params,
};
const response: AxiosResponse = await axios.get(
`${baseUrl}${path}`,
object
);
return response;
});
}
(obj contains the headers and is defined earlier in the file; baseUrl is a constant which I import).
So, if I have a useEffect to retrieve data from the endpoint '/user/{userId}' whenever the state variable userId changes, I do this:
React.useEffect(() => {
const controller = new AbortController();
const getData = async () => {
try {
const url = `user/${userId}`;
let res = await Client.getData(url, {
signal: controller.signal,
});
... Do things with results ...
} catch (e) {
// Show error
if (!controller.signal.aborted) console.log('Error: ', e);
}
};
getData();
return () => {
controller.abort();
};
}, [state.userId]);
I'm just a bit confused about how errors will be handled in this code. So, if there's an error when the axios call is made (eg no network connection, the endpoint is wrong, or the user isn't found or whatever) will the catch block get called in the getData function? Or do I need a try...catch in the api component too?

axios returns promise instead of data

I am querying some data from IPFS using axios, the problem is that after calling the specific api the return value is a promisse from axios.
const getNFTDetail = async (url: string) => {
const urlIPF = url.replace("ipfs://", "https://cloudflare-ipfs.com/ipfs/");
try {
return await axios.get(urlIPF).then((res) => {
return res.data;
});
} catch (error) {
console.log(error);
}
};
response I get:
is there a way to wait until promisse has been resolved?, as you see I am already using async await on the function call.
just, decide if you use async / await or .then / .catch:
const getNFTDetail = async (url: any) => {
const urlIPF = url.replace("ipfs://", "https://cloudflare-ipfs.com/ipfs/");
const { data } = await axios.get(urlIPF);
return data;
};
or
const getNFTDetail = (url: any) => {
const urlIPF = url.replace("ipfs://", "https://cloudflare-ipfs.com/ipfs/");
axios.get(urlIPF).then(({data}) => {
// use your data here
}).catch((err)=>{
console.log(err);
};
};
When you fetch a request, no matter any http client you use, will then return a Promise.
Just use await to get a response from your request.
const response = await axios.get(your-url);
const json = await response.json();
To use typescript correctly, type the url a string: (url: string) instead of happy any type.

Error: Invalid hook call. when calling hook after await - how do you await for data from one hook to instantiate into another?

Im trying to inject a header into my fetcher before using swr to fetch the data. I need to await for a custom hook to respond with the data before I can inject it into the custom fetcher.
If I use a promise.then I know i'm getting the relevant data, and if I manually inject it using a string it works and i see the header. Its just doing it async
How should I go about doing this?
Code:
export const useApi = async (gql: string) => {
const { acquireToken } = useAuth()
await acquireToken().then(res => { graphQLClient.setHeader('authorization', `Bearer ${res.accessToken}`) })
const { data, error } = useSWR(gql, (query) => graphQLClient.request(query));
const loading = !data
return { data, error, loading }
}
first, keep consistent your promises, use async/await or choose for chaining it with then, but not both. if you await acquireToken() you can store its value in variable. also, if you choose for async/await wrap your code with a try/catch block, for handling errors properly:
export const useApi = async (gql: string) => {
const { acquireToken } = useAuth()
try {
const res = await acquireToken()
graphQLClient.setHeader('authorization', `Bearer ${res.accessToken}`)
const { data, error } = useSWR(gql, (query) => graphQLClient.request(query))
const loading = !data
return { data, error, loading }
catch(error) {
// handle error
}
}

Axios Error Networ error on request Google place api

im trying to make a request to google api but returns me network error. If i put the url in the browser, brings me the information correctly.I tryed to formate the request without success. The google places search works correctly too.
export const fetch_information = (skip, limit, filter) => async (dispatch) => {
try {
var url = `https://maps.googleapis.com/maps/api/place/details/json?place_id=ChIJk0aJYPbk3JQRLpKN20Jecko&fields=name,rating,formatted_phone_number&key=MyKey`;
const {data} = await axios.get(url)
console.log(data)
} catch (error) {
console.log(error.message)
}
}
and
export const fetch_information = (skip, limit, filter) => async (dispatch) => {
try {
var url = `https://maps.googleapis.com/maps/api/place/details/json?`;
let config = {
params: {
place_id: 'ChIJk0aJYPbk3JQRLpKN20Jecko',
key: 'myKey',
},
}
const {data} = await axios.get(url, config)
console.log(data)
} catch (error) {
console.log(error.message)
}
}
I think that the request looks a bit messy. I'm under the impression that you are trying to pass results to a redux store. Let's see if we can clean this up a bit.
export const fetch_information = async () => dispatch => {
const req = await axios.get("https://maps.googleapis.com/maps/api/place/details/json?place_id=ChIJk0aJYPbk3JQRLpKN20Jecko&fields=name,rating,formatted_phone_number&key=MyKey");
const data = await req.json();
return data;
//or, for your purpose...
console.log(data);
//can also dispatch for store
}
I didn't see anything you were passing as necessary for this.

Can't get response from ipify using fetch in React

In my React app, I want to get the IP address of the user at client side. I intended to use ipify for that. When I'm using 'http://api.ipify.org/?format=json' in the browser, it successfully returns {"ip":"112.135.11.128"}, but I can't get the same response when I'm making request through fetch API. What I get is something like below.
code:
import React, { useEffect } from 'react';
const QRDisplay = () => {
async function getIP(){
const response = await fetch('https://api.ipify.org/?format=json');
const data = await response.json();
return response.status === 200 ? data : "err"
}
useEffect( () => {
getIP().then(data => console.log(data))
},[])
return (
<>
</>
);
};
export default QRDisplay;
You need to call .json() method to get body.
async function getIP(){
const response = await fetch('http://api.ipify.org/?format=json');
const data = await response.json();
return data;
}
Then you can use it like so:
getIP().then(data => console.log(data);
Similar approach to Ozan Bulut
await fetch('http://api.ipify.org/?format=json')
.then(response => response.json())
.then(data => {
/* use data here */
});

Resources