Jakub Koudela
Jakub Koudela

Reputation: 180

Dynamic, multiple API calls using axios

Iam trying to fetch data from API server.

  async function fetchData() {
  const results = await axios(`/api/autotask/config-items/${props.accountID}`);

  const contracts = results.data.map(t => axios(`/api/autotask/contract/${t.contractID}`).catch(err => err))
  const products = results.data.map(l => axios(`/api/autotask/product/${l.productID}`).catch(err => err))
  const subscriptions = results.data.map(s => axios(`/api/autotask/subscription/${s.id}`).catch(err => err))

  Promise.all([[...contracts], [...products], [...subscriptions]])
    .then(response => {
      console.log(response)

    })
}

This will first get list of items based on accountID. Each item has contractID, productID and id. These are passed to 3 other Axios GET calls (contracts, products, subscriptions)

So far this works, however when I use Promise.all I will get 3 arrays with more promises inside rather than actual resolved data.

(3) [Array(7), Array(7), Array(7)]
0: (7) [Promise, Promise, Promise, Promise, Promise, Promise, Promise]
  0: Promise {<fulfilled>: {…}}
  1: Promise {<pending>}
  2: Promise {<pending>}
  3: Promise {<pending>}
  4: Promise {<fulfilled>: {…}}
  5: Promise {<pending>}
  6: Promise {<pending>}
  length: 7
  __proto__: Array(0)
1: (7) [Promise, Promise, Promise, Promise, Promise, Promise, Promise]
2: (7) [Promise, Promise, Promise, Promise, Promise, Promise, Promise]
  length: 3
  __proto__: Array(0)

With this, I can access response[0], response[1] or response[2] but it will have just promises again. When I tried to spread each array Promise.all([**...[...contracts]**, [...products], [...subscriptions]]) it will spread it and I get the data but won be able to access it by array anymore. Hope this makes sense. Basically what I am trying to get out of this is the individual arrays containing data from API. I've been looking int this for past 2 days but I am not going anywhere. I've looked at many videos and articles but it still not making much sense. I am sure that I am doing something wrong, maybe even taking a completely wrong approach. It would be great to get some insight and a little bit of help. Thank you

Upvotes: 1

Views: 610

Answers (1)

Terry Lennox
Terry Lennox

Reputation: 30685

We can use await here along with Promise.all for each item, e.g. contracts, products, subscriptions, using a little de-structuring to pull out the data property from each response.

When we do this we'll get a list of the axios responses for each item type, so we'll need to just pick out the data.

async function fetchData() {
    try {
        const results = await axios(`/api/autotask/config-items/${props.accountID}`);
    
        // This will get a list of axios responses for each item, e.g. { data: [1,2,3] .... }; Use { data } => destructing to get data.
        const contracts = await Promise.all(results.data.map(t => axios(`/api/autotask/contract/${t.contractID}`).then( ({data}) => data) ));
        const products = await Promise.all(results.data.map(l => axios(`/api/autotask/product/${l.productID}`).then( ({data}) => data) ));
        const subscriptions = await Promise.all(results.data.map(s => axios(`/api/autotask/subscription/${s.id}`).then( ({data}) => data) ));

        console.log("Result:", { contracts, products, subscriptions } );
    } catch (error) {
        // We need to make sure we log any error..
        console.log("fetchData: an error occurred:", error);
    }
}

And a snippet (using mocked data):

// Mock out axios for demo purposes
async function axios(input) {
    if (input.includes('config-items')) {
        return { data: [1,2,3,4,5].map(n => { return { id: n, contractID: n, productID: n }}) } ;
    } else { 
        return { data: { type: input.split("/")[3] } };
    }
}

let props = { accountID: 'accountID' };

async function fetchData() {
    try {
        const results = await axios(`/api/autotask/config-items/${props.accountID}`);
    
        // This will get a list of axios responses for each item, e.g. { data: [1,2,3] .... };
        const contracts = await Promise.all(results.data.map(t => axios(`/api/autotask/contract/${t.contractID}`).then( ({data}) => data) ));
        const products = await Promise.all(results.data.map(l => axios(`/api/autotask/product/${l.productID}`).then( ({data}) => data) ));
        const subscriptions = await Promise.all(results.data.map(s => axios(`/api/autotask/subscription/${s.id}`).then( ({data}) => data) ));

        console.log("Result:", { contracts, products, subscriptions } );
    } catch (error) {
        // We need to make sure we log any error..
        console.log("fetchData: an error occurred:", error);
    }
}

fetchData();

Upvotes: 1

Related Questions