Charles de Jager
Charles de Jager

Reputation: 41

JavaScript Recursively call Axios.get

I have an API that returns a Parent Child relationship with multiple records

First call to API http://someAPI/getResult/?parent=null will give me:

{
   ParentID: null,
   Id: 1,
   Name: 'Top Level Element'
}

Second call should be to http://someAPI/getResult/?parent=1 and that will return:

[
  {
    ParentID: 1,
    ID: 2,
    Name:  'Second Level Element First Element'
  },
  {
    ParentID: 1,
    ID: 3,
    Name:  'Second Level Element Second Element'
  }
]

The next should be http://someAPI/getResult/?parent=2 and then http://someAPI/getResult/?parent=3. Those will return their own children until finally no children are returned.

How can I write a recursive function that will retrieve all entries from the top level (ParentID = null) until the last child (no further records)?

Upvotes: 0

Views: 952

Answers (2)

Mulan
Mulan

Reputation: 135377

Mutual recursion is a great way to build trees -

const fetchJson = (url = "") =>
  fetch(url).then(r => r.json())

const getResult = (parent = null) =>
  fetchJson(`http://someAPI/getResult/?parent=${parent}`)
    .then(children => Promise.all(children.map(getResultAux))) // <-- calls getResultAux

const getResultAux = async (t = {}) =>
  ({ ...t, children: await getResult(t.id) })  // <-- calls getResult
const result =
  await getResult() // default parent = null

console.log(result)
[
  {
    parentId: null,
    id: 1,
    name: 'Top Level Element',
    children:
       [ 
         {
           parentId: 1,
           id: 2,
           name: 'Second Level Element First Element',
           children: [ { ... }, { ... }, ... ]
         },
         {
           parentId: 1,
           id: 3,
           name: 'Second Level Element Second Element',
           children: [ ... ]
         }
      ]
  }
]

Upvotes: 3

AKX
AKX

Reputation: 169308

It might be simplest to handle the recursion with a manual stack.

As this is an async function, it will return a Promise that should eventually resolve to an object containing the responses for each parent=...

async function getTree() {
  const idsToCheck = ["null"];
  const results = {};
  while (idsToCheck.length) {
    const id = idsToCheck.shift();
    if (results[id]) {
      // We've already processed this node
      continue;
    }
    const resp = await fetch("http://someAPI/getResult/?parent=" + id);
    if (!resp.ok) throw new Error("response not ok");
    const data = await resp.json();
    results[id] = data;
    data.forEach((child) => {
      idsToCheck.push(child.Id);
    });
  }
  return results;
}

(Another formulation that uses actual recursive function calls:

async function getTree() {
  const results = {};
  async function populateResults(id) {
    if (results[id]) {
      // We've already processed this node
      return;
    }
    const resp = await fetch("http://someAPI/getResult/?parent=" + id);
    if (!resp.ok) throw new Error("response not ok");
    const data = await resp.json();
    results[id] = data;
    for (let child of data) {
      await populateResults(results, child.Id);
    }
  }
  await populateResults("null");
  return results;
}

)

Upvotes: 3

Related Questions