Join us at FabCon Atlanta from March 16 - 20, 2026, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.
Register now!Learn from the best! Meet the four finalists headed to the FINALS of the Power BI Dataviz World Championships! Register now
I have coded the following function, which recursively calls itself in order to retrieve the full list of users from a REST API:
let
GetUserData = (startFrom as number, uCount as number, result) =>
let
userCount = if uCount <> null then
uCount
else
Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/count",
[Headers=[Accept="application/vnd.api+json",#"X-Authorization-Key"= Text.From(#"PUSapikey")]])),
userResult = Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/?From=" & Text.From(startFrom),
[Headers=[Accept="application/vnd.api+json",#"X-Authorization-Key"= Text.From(#"PUSapikey")]])),
// See if more need to be read
combinedResult = List.Distinct(List.Combine(userResult, result)),
startFrom = if userCount < List.Count(combinedResult) then List.Count(combinedResult) else null,
#"Converted to Table" = Record.ToTable(combinedResult),
#"Expanded Value" = Table.ExpandListColumn(#"Converted to Table", "Value"),
#"Expanded Value1" = Table.ExpandRecordColumn(#"Expanded Value", "Value", {"links", "firstName", "lastName", "middleName", "fullName", "title", "location", "department", "notes", "isAnonymized", "isSuperuser", "role", "notificationScheme", "highlightNotifications", "flushNotifications", "accessKeyNonceId", "pictureId", "emailAddressId", "phonenumberId", "addressId", "companyId", "companyDepartmentId", "companyLocationId", "languageId", "credentialsId", "unavailable", "unavailableChangedById", "unavailableChangedByDate", "disabled", "importUniqueKey", "cf_1", "cf_2", "cf_3", "cf_4", "cf_5", "cf_6", "cf_7", "cf_8", "cf_9", "type", "id", "created", "modified", "createdById", "modifiedById"}, {"Value.links", "Value.firstName", "Value.lastName", "Value.middleName", "Value.fullName", "Value.title", "Value.location", "Value.department", "Value.notes", "Value.isAnonymized", "Value.isSuperuser", "Value.role", "Value.notificationScheme", "Value.highlightNotifications", "Value.flushNotifications", "Value.accessKeyNonceId", "Value.pictureId", "Value.emailAddressId", "Value.phonenumberId", "Value.addressId", "Value.companyId", "Value.companyDepartmentId", "Value.companyLocationId", "Value.languageId", "Value.credentialsId", "Value.unavailable", "Value.unavailableChangedById", "Value.unavailableChangedByDate", "Value.disabled", "Value.importUniqueKey", "Value.cf_1", "Value.cf_2", "Value.cf_3", "Value.cf_4", "Value.cf_5", "Value.cf_6", "Value.cf_7", "Value.cf_8", "Value.cf_9", "Value.type", "Value.id", "Value.created", "Value.modified", "Value.createdById", "Value.modifiedById"}),
#"Removed Columns" = Table.RemoveColumns(#"Expanded Value1",{"Name"})
in
if startFrom <> null then
@GetUserData(startFrom, userCount, combinedResult)
else
#"Removed Columns"
in
GetUserData
When I try to call the function, or invoke it from Power Query, I get the cyclic reference error.
Could one of you PQ masters out there help me tackle this issue?
Solved! Go to Solution.
Your first steps are correct
let
userCount = Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/count",
[
Headers=[
Accept="application/vnd.api+json",
#"X-Authorization-Key"= Text.From(#"PUSapikey")
]
]))[count],
pages = Number.RoundUp(userCount / 500),
but then you veer off track. Next step is to create a list with all the URLs you need to fetch the data chunks.
since you already know the number of pages you need there is not really a reason to use list.generate any more. A simple
{1..pages}
is enough. Convert that to a table, add your GetUserData function as a custom column, and combine the output.
Ok, so I am trying List.Generate, but for some reason my resulting list seems endless. The function GetUserData performs a web call to return a list of Users (one page = 500 items). So I want to call this function with multiple pages. However, as I said, it seems not to stop.
Perhaps my lack of understanding of variable scope - for example, that I must defined pageNumber outside the List.Generate() construct, otherwise I get an error. Any advice and enlightment on scoping is greatly appreciated!
let
userCount = Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/count",
[
Headers=[
Accept="application/vnd.api+json",
#"X-Authorization-Key"= Text.From(#"PUSapikey")
]
]))[count],
pages = Number.RoundUp(userCount / 500),
pageCount = 0,
Result = {},
totalUserList = List.Generate(
() => [
pageCount = 1,
Result = GetUserData(pageCount)
],
each pageCount <= pages,
each [
pageCount = pageCount + 1,
Result = GetUserData(pageCount)
]
),
#"Converted to Table" = Table.FromList(totalUserList, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"Result"}, {"Column1.Result"}),
#"Column1 Result1" = #"Expanded Column1"{0}[Column1.Result],
#"Converted to Table1" = Table.FromList(#"Column1 Result1", Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Expanded Column2" = Table.ExpandRecordColumn(#"Converted to Table1", "Column1", {"links", "firstName", "lastName", "middleName", "fullName", "title", "location", "department", "notes", "isAnonymized", "isSuperuser", "role", "notificationScheme", "highlightNotifications", "flushNotifications", "accessKeyNonceId", "pictureId", "emailAddressId", "phonenumberId", "addressId", "companyId", "companyDepartmentId", "companyLocationId", "languageId", "credentialsId", "unavailable", "unavailableChangedById", "unavailableChangedByDate", "disabled", "importUniqueKey", "cf_1", "cf_2", "cf_3", "cf_4", "cf_5", "cf_6", "cf_7", "cf_8", "cf_9", "type", "id", "created", "modified", "createdById", "modifiedById"}, {"links", "firstName", "lastName", "middleName", "fullName", "title", "location", "department", "notes", "isAnonymized", "isSuperuser", "role", "notificationScheme", "highlightNotifications", "flushNotifications", "accessKeyNonceId", "pictureId", "emailAddressId", "phonenumberId", "addressId", "companyId", "companyDepartmentId", "companyLocationId", "languageId", "credentialsId", "unavailable", "unavailableChangedById", "unavailableChangedByDate", "disabled", "importUniqueKey", "cf_1", "cf_2", "cf_3", "cf_4", "cf_5", "cf_6", "cf_7", "cf_8", "cf_9", "type", "id", "created", "modified", "createdById", "modifiedById"}),
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column2",{"links"})
in
#"Removed Columns"
Your first steps are correct
let
userCount = Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/count",
[
Headers=[
Accept="application/vnd.api+json",
#"X-Authorization-Key"= Text.From(#"PUSapikey")
]
]))[count],
pages = Number.RoundUp(userCount / 500),
but then you veer off track. Next step is to create a list with all the URLs you need to fetch the data chunks.
since you already know the number of pages you need there is not really a reason to use list.generate any more. A simple
{1..pages}
is enough. Convert that to a table, add your GetUserData function as a custom column, and combine the output.
Brilliant!! Thanks so much for your help! I keep forgetting to use the powerful features provided in the UI.
That looks promising. Thanks for the tip! However, I have seen a lot of examples with recursion. How do you get this to work without triggering a cyclic reference error?
- don't use recursive functions for this. Use List.Generate instead.
- try not to do any transforms until after you combined the data.
Share feedback directly with Fabric product managers, participate in targeted research studies and influence the Fabric roadmap.
Check out the February 2026 Power BI update to learn about new features.