axios get - multiple api calls with response from first api to subsequent calls - axios

How to make multiple api calls with axios - when I have to pass a value from my first api response to all subsequent calls. I have 2 other calls to be made inside getData function where I have to pass a value from y first api response {data} - how to chain multipl requests with axios? 2 next calls are dependent on first call - they are not dependant on each other - they can happen in parallel - the only issue I have is - I am not able to pass the response data to the subsequent end-points.
import Request from 'axios';
export function getData() {
return async function getData(dispatch) {
const { data } = await getDatafromService();
dispatch({ type: 'Data_fetch', payload: data });
};
}
async function getDatafromService() {
const endpoint = "api-url";
return Request.get(endpoint);
}

Something like this should work for an overall structure.
The async function getData will ultimately return an array of the responses from the last two requests.
import Request from 'axios';
export function getData() {
return async function getData(dispatch) {
const { data } = await getDatafromService();
return Promise.all([
sendDataToFirstService(data),
sendDataToSecondService(data),
])
};
}
function getDatafromService() {
const endpoint = "api-url";
return Request.get(endpoint);
}
function sendDataToFirstService(data) {
const endpont = "first-url";
return Request.post(endpoint, data)
}
function sendDataToSecondService(data) {
const endpont = "second-url";
return Request.post(endpoint, data)
}
Note that you may need to modify the data received from the original get request before passing it to the next two.
You can do this by chaining .then onto the Promise like so...
function getDatafromService() {
const endpoint = "api-url";
return Request.get(endpoint).then(({data}) => modify(data));
}

Related

How to use refetch method to send different queries using useQuery in react-query

I'm working with react-query in ReactJS to build a website.
I have the following code, where I fetch some data using useQuery():
const { error, data: movie, status, refetch } = useQuery({
queryKey: 'key1',
queryFn: async () => {
return await Promise.all([
axios.get(`API-1.com/get-some-data`), /*getting some data from api-1 */
axios.get(`API-2.com/get-some-data`), /*getting some data from api-2 */
]).then(([api1, ap2]) => {
return { data1: api1, data2: api2 }
})
}
})
The problem I'm facing is getting somtimes a 404 response from one of the apis, so I need to refetch the data just from the other api that doesn't cause the error.
I tried to use the refetch method inside onError, but it can't be used with parameters.
onError: (error) => {
refetch() /* refetch can't be used with parameters */
},
How can I handle this problem?
I ended up doing the following:
Writing the fetching part in an external function (so I can call the function with parameters)
Adding a try-catch block inside the queryFn to handle the errors
/********* this is the function where I fetch the data. *********/.
/********* with a param that tells me if i'll call API-2 or not *********/
const fetchData = async ({ isDataFoundInApi2 }) => {
return await Promise.all([
axios.get(`API-1.com/get-some-data`),
(!isDataFoundInApi2 && axios.get(`API-2.com/get-some-data`)),
]).then(([api1, api2]) => {
return { data1: api1, data2: api2 }
})
/********* the useQuery where the above method is called *********/
/********* first it sends true as a bool value, then if no *********/
/********* data was found in API-2, it sends false *********/
/********* from `catch` to prevent the fetching from API-2 *********/
const { error, data: movie, status } = useQuery({
queryKey: 'key1',
queryFn: async () => {
try {
return await fetchData({})
} catch (error) {
if (error.response?.status === 404)
return await fetchData({ isDataFoundInApi2: true }) // true means call only the first api
}
},
})

How to get data from react query "useQuery" hook in a specific type

When we get data from useQuery hook, I need to parse the data a specific type before it return to user. I want data which return from useQuery hook should be of "MyType" using the parsing function i created below. I am unable to find method to use my parsing function. Is there any way to do it? I don't want to rely on schema structure for data type.
type MyType = {
id: number;
//some more properties
}
function parseData(arr: any[]): MyType[]{
return arr.map((obj, index)=>{
return {
id: arr.id,
//some more properties
}
})
}
const {data} = await useQuery('fetchMyData', async ()=>{
return await axios.get('https://fake-domain.com')
}
)
I would take the response from the api and transform it inside the queryFn, before you return it to react-query. Whatever you return winds up in the query cache, so:
const { data } = await useQuery('fetchMyData', async () => {
const response = await axios.get('https://fake-domain.com')
return parseData(response.data)
}
)
data returned from useQuery should then be of type MyType[] | undefined
There are a bunch of other options to do data transformation as well, and I've written about them here:
https://tkdodo.eu/blog/react-query-data-transformations
I think you should create your own hook and perform normalisation there:
const useParseData = () => {
const { data } = await useQuery('fetchMyData', async () => {
return await axios.get('https://fake-domain.com')
}
return parseData(data)
}
And where you need this data you could just call const parsedData = useParseData()

Http get request URL shows [object promise]

I am trying to use web api call get method to access data and display in my page. My url would be something like: https://localhost:44399/api/APIOrder/GetUserOrder?email=xxx#gmail.com to be able to display the data.
However, when I combine my url with a variable,it doesn't display anything and console log shows the url in https://localhost:44399/api/APIOrder/GetUserOrder?email=[object Promise]. Is there any way to let the url read my this.User variable?
please review my getUserOrder()
User = this.storage.get('currentUser');
constructor(private http:Http,public storage: Storage){
}
public getUserOrder()
{
var url="https://localhost:44399/api/APIOrder/GetUserOrder?email=";
console.log(url+this.User);
return this.http.get(url+this.User).map(res=>res.json());
}
I am really new to this. Pls tell me if i am unclear. Any help would be much appreciated..
UPDATE
It shows undefined because it accessed the variable value on top but not from ionViewWillEnter
User:string;
constructor(private http:Http,public storage: Storage){
}
async ionViewWillEnter()
{
this.User = await this.storage.get('currentUser');
}
public getUserOrder()
{
var url="https://localhost:44399/api/APIOrder/GetUserOrder?email=";
console.log(url+ this.User);
return this.http.get(url+this.User).map(res=>res.json());
}
You should await the return of the Promise. You can do this inside the constructor or inside a lifecyle like ionViewWillEnter()
User: string;
async ionViewWillEnter() {
this.User = await this.storage.get('currentUser');
}
Answer here: "This is the expected result."
UPDATE
This is a different approach: if your function is directly called somehow, you can create a function which returns the variable from storage. If the data is found, proceed with the http request.
async getUserOrder() {
const user = await this.getUserFromStorage();
if (user) {
var url="https://localhost:44399/api/APIOrder/GetUserOrder?email=";
return this.http.get(url + user).map(res=>res.json());
}
}
async getUserFromStorage(): Promise<string> {
return await this.storage.get('currentUser');
}

Get data from subscribe in Ionic

I'm having difficulty getting data with subscribe in the constructor of an Ionic page, basically I need to do the subscribe to get a list and show to the user, but I get undefinied
In my constructor, I do this:
this.getUser(this.auth.currentUser().uid);
console.log(this.user);
My getUser():
getUser(uid) {
const self = this;
this.auth.getUserData(uid).subscribe(function(doc) {
if (doc.exists) {
self.user = doc.data();
} else {
console.log("No such document!");
}
});
};
But, when i call other function with button, i get the data:
userf(){
console.log(this.user);
}
Obs: I use Firestore
The reason it gives you undefined is because your method “getUser” is async and when you call console.log the user value is not yet obtained.
So you should access user value inside your getUser method after it is received.
Now also you are trying to pass “this” into the getUser method with const. start using fat arrow functions which do not create their own scope (this):
getUser(uid) {
this.auth.getUserData(uid).subscribe((doc) => {
if (doc.exists) {
this.user = doc.data();
} else {
console.log("No such document!");
}
});
};

api request returns undefined

maybe is a stupid question but,
when I'm calling api from 'outside' function it always returns undefined,
for example:
actions.js
import axios from 'axios'
export function getProducts() {
axios.get('http://localhost:8000/api/products').then((response) => {
return response;
});
}
and then in a component:
mounted() {
this.products = getProducts();
console.log(this.products);
}
returns undefined
of course when I make a request from component it returns result
mounted() {
axios.get('http://localhost:8000/api/products').then((response) => {
this.products = response;
console.log(this.products);
});
}
Why is this happening and how can I solve this problem?
Thanks
You are returning the response value in the then callback of the axios.get call. However, your getProducts function doesn't return anything.
Simply return the axios.get call:
export function getProducts() {
return axios.get('http://localhost:8000/api/products');
}
Then, the result of getProducts will be the Promise returned by axios.get(). So, you can add a then callback on the result of getProducts and set you this.products that way:
mounted() {
getProducts().then(products => this.products = products);
}