I am trying to write a recursive fetch function. I am calling an endpoint that accepts a name param and returns their role
and an array of direct-subordinates
like so:
{
role: "CEO",
direct-subordinates: [ "john smith", "bob jones" ]
}
I then want to call the function again to request the same data for each subordinate.
Here is the code I have:
export const fetchEmployee = async (name) => {
let url = `https://url.com/to/employees/endpoint/${name}`
let req = await fetch(url)
let json = await req.json()
return json
}
export const recursiveFetchEmployees = async (initialName) => {
let json = await fetchEmployee(initialName)
const role = json[0]
const subordinates = json[1]
if (subordinates) {
return {
name: initialName,
role: role,
subordinates: subordinates['direct-subordinates'].map(async (subordinate) => {
let result = await recursiveFetchEmployees(subordinate)
return result
}),
}
} else {
return {
name: initialName,
role: role,
}
}
}
This almost works when called with recursiveFetchEmployees(employeeName).then((resp) => console.log(resp))
but the result is:
name: "robert robertson",
role: "CEO",
subordinates: (2) [Promise, Promise],
How do I change this so the function works its way down the employee hierarchy recursively producing a result like this:
{
name: "robert robertson",
role: "CEO",
subordinates: [
{
name: "john smith",
role: "Marketing Manager",
subordinates: [{
name: "mary doyle",
role: "employee",
}]
},
{
name: "bob jones",
role: "Development Manager",
subordinates: [{
name: "barry chuckle",
role: "Development Lead",
subordinates: [{
name: "billy bob",
role: "Developer",
}]
}]
},
],
}
Thanks in advance for any help or advice.
EDIT / UPDATE
Thanks to the fine answer given by @trincot the problem I had was resolved but it introduced another problem. I need to check for and filter out duplicates in the returned results. I introduced a uniqueNameArray
that gets initialised with an empty array and on every call, it adds the name of the current initialName
param if it does not already exist in the array. Here is my code:
export const recursiveFetchEmployees = async (initialName, uniqueNameArray = []) => {
if (!uniqueNameArray.includes(initialName)) {
uniqueNameArray.push(initialName)
let json = await fetchEmployee(initialName)
const role = json[0]
const subordinates = json[1]
if (subordinates) {
return {
name: initialName,
role: role,
subordinates: await Promise.all(
subordinates['direct-subordinates'].map(
(subordinate) => subordinate && recursiveFetchEmployees(subordinate, uniqueNameArray)
)
),
}
} else {
return {
name: initialName,
role: role,
}
}
}
}
Unfortunately when there is a duplicate it still gets called in the map function resulting in a subordinates
array that looks like this:
{
name: "bob jones",
role: "Development Manager",
subordinates: [
{
name: "barry chuckle",
role: "Development Lead",
subordinates: [{
name: "billy bob",
role: "Developer",
}]
},
{
name: "james jameson",
role: "Development Lead",
subordinates: [{
name: "joey joe joe junior",
role: "Developer",
}]
},
undefined, // <-- This is where there was a duplicate
]
},
Is there a way to omit it from the promise list? What ive done above should do that as far as I can tell so Im not sure why it still returns an undefined response.
As always, any help is appreciated, thanks!
It is no surprise that .map(async ...
returns an array of promise objects, as an async
function always returns a promise.
You could use Promise.all
here:
subordinates: await Promise.all(
subordinates['direct-subordinates'].map(recursiveFetchEmployees)
),
Note also that you can just pass recursiveFetchEmployees
as callback argument to .map
. There is no need to create that wrapper function.