Find everything you need to get certified on Fabric—skills challenges, live sessions, exam prep, role guidance, and more.
Get startedGrow your Fabric skills and prepare for the DP-600 certification exam by completing the latest Microsoft Fabric challenge.
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.
Ask questions in Eventhouse and KQL, Eventstream, and Reflex.
Check out the May 2024 Power BI update to learn about new features.