I have my custom axios hook, to send data without files it works perfectly, but when I send files it does not recognize any data.
......
const axiosFetch = async (params) => {
const { method, url, data } = params;
try {
setLoading(true);
const control = new AbortController();
setController(control);
const res = await axios[method.toLowerCase()](url, {
...data,
signal: control.signal,
});
setResponse(res.data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
......
If I modify this part, the file upload works, but it loses the signal. How can I implement both properties.
const res = await axios[method.toLowerCase()](url, data);
For the POST, PUT, and PATCH requests data and configuration are the second and third arguments.
See Instance Methods
Try instead:
const res = await axios[method.toLowerCase()](
url,
data,
{ signal: control.signal }
);
For GET, DELETE, HEAD, and OPTIONS requests, omit the data argument.
const res = await axios[method.toLowerCase()](
url,
{ signal: control.signal }
);
You'll need to split these request types out logically.
Alternatively you can use a request config:
const res = await axios({
url,
method: method.toLowerCase(),
data,
signal: control.signal,
});
Related
so I have 2 post data functions, the first is to upload photo/file, another one is for add a document.
in the API for add document, there are 3 body that need to be filled. name(string), location(string), and photo(string).
I already created the function for upload photo, and I get the return link of the url path for photo.
My question is, how do I assign the link from url path to body add document for photo(string)?
json for add document :
json for uploaded photo:
code for upload photo:
try {
const postFileReq = await axios.post(
"https://spda-api.onrender.com/api/file/upload",
formData,
options
);
const postFileRes = await postFileReq.data.image;
if (postFileReq.status === 200) {
setPhotoUrl(postFileRes);
console.log("postFileRes", postFileRes);
// console.log("photoUrl", photoUrl);
}
} catch (error) {
const err = error as AxiosError;
console.log(err.response?.data);
}
code for add document:
try {
const postDocReq = await axios.post(
"https://spda-api.onrender.com/api/admin/documents",
{
name: field.name,
location: field.location,
photo: photoUrl,
},
{
headers: {
"Content-Type": "application/json",
authorization: `Bearer ${token}`,
},
}
);
const postDocRes = await postDocReq.data;
if (postDocReq.status === 200) {
setShowSnackbar(true);
router.reload();
console.log(postDocRes);
}
} catch (error) {
const err = error as AxiosError;
console.log(err.response?.data);
}
i already tried using useState to assign but it still not working, anyone have an idea?
const [photoUrl, setPhotoUrl] = useState("");
My complete code: https://pastebin.com/Rb5xX08z
Alright so what you need you to do is call the second api in the success method of the first call. I will jump to the code directly with async/await. You can do it with then as well.
You can handle it inside your if condition 200 success. So like once it is successfull call the second function then. But I have shown with async/await like mentioned
import axios from 'axios'
const MyComponent = () => {
const [data, setData] = useState(null);
const [secondData, setSecondData] = useState(null);
const fetchData = async () => {
try {
const response = await axios.get('https://first-api.com');
setData(response.data);
//if first api was successful,call the second api
const secondResponse = await axios.get(`https://second-api.com/${response.data.id}`);
setSecondData(secondResponse.data);
} catch (error) {
console.error(error);
}
};
useEffect(() => {
fetchData();
}, []);
return (
<div>
<p>Data from first API: {JSON.stringify(data)}</p>
<p>Data from second API: {JSON.stringify(secondData)}</p>
</div>
);
};
I started learning Remix and got to a point where I would like to get some data from APIs. I created a loader function, in routes folder (initially I did this in component, which is wrong), where I fetch my API call:
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
return json(await res.json());
}
After that I used the data in my component, where needed:
const { data } = useLoaderData();
Now I would like to use another API, but I don't know how properly to do that in the loader function
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
// second API i would like to use but don't know how :(
const faqRes = await fetch("https://jsonplaceholder.typicode.com/posts");
return json(await res.json());
}
How could I use multiple APIs in Remix?
You can return more data:
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
const faqRes = await fetch("https://jsonplaceholder.typicode.com/posts");
return json({
res: await res.json(),
faqRes: await faqRes.json()
});
}
Then in your component:
const { res, faqRes } = useLoaderData();
What if you want to wait for 1st API data and pass the response to 2nd API?
e.g.
export async function loader() {
const res = await fetch("https://reqres.in/api/users?page=2");
const faqRes = await fetch(`https://jsonplaceholder.typicode.com/posts/${res.userId}`);
return json({
faqRes: await faqRes.json()
});
}
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?
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.
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.