Reputation: 1061
I am trying to call an API using m query, to create custom connector in Power BI.
Here is my M Query
shared ConnectWiseManage.Contents = () => ConnectWiseManageNavTable(BaseUrl) as table;
ConnectWiseManageNavTable = (url as text) as table =>
let
entitiesAsTable = Table.FromList(RootEntities, Splitter.SplitByNothing()),
rename = Table.RenameColumns(entitiesAsTable, {{"Column1", "Name"}}),
withData = Table.AddColumn(rename, "Data", each ConnectWiseManage.Feed(Uri.Combine(url, [Name])), Uri.Type),
withItemKind = Table.AddColumn(withData, "ItemKind", each "Table", type text),
withItemName = Table.AddColumn(withItemKind, "ItemName", each "Table", type text),
withIsLeaf = Table.AddColumn(withItemName, "IsLeaf", each true, type logical),
navTable = Table.ToNavigationTable(withIsLeaf, {"Name"}, "Name", "Data", "ItemKind", "ItemName", "IsLeaf")
in
navTable;
//Basic Auth Implementation
ConnectWiseManage.Feed = (url as text) =>
let
Page = if url = null then {} meta [nextUrl = null] else
let
PasswordAPIKey = Text.Split(Extension.CurrentCredential()[Password], "+"),
username = Extension.CurrentCredential()[Username],
userpass = List.First(PasswordAPIKey),
basicAuth = Binary.ToText(Text.ToBinary(Text.Combine({username, ":", userpass}))),
source = Web.Contents(url,
[
ManualCredentials = true,
Headers = [#"Authorization" = Text.Combine({"Basic ", basicAuth}), #"clientid" = clientid]
//ManualStatusHandling = {403, 404} // Useful for debugging.
]),
content =source,
nextUrl = GetNextLink(content),
objects = Json.Document(content),
// json = Json.Document(source)
asTable = Table.FromList(objects, Splitter.SplitByNothing()),
fields = Record.FieldNames(Table.FirstValue(asTable, [Empty = null])),
expandAll = Table.ExpandRecordColumn(asTable, "Column1", fields)
in
expandAll meta [nextUrl = nextUrl]
in
Page;
GetNextLink = (response) =>
let
// The "Link" header is not accessible in Power Query, hence this Data Connector.
link = Value.Metadata(response)[Headers][Link]?,
links = Text.Split(link, ","),
splitLinks = List.Transform(links, each Text.Split(Text.Trim(_), ";")),
next = List.Select(splitLinks, each Text.Trim(_{1}) = "rel=""next"""),
first = List.First(next),
removedBrackets = Text.Range(first{0}, 1, Text.Length(first{0}) - 2)
in
try removedBrackets otherwise null;
//Common functions
Table.ToNavigationTable = (
table as table,
keyColumns as list,
nameColumn as text,
dataColumn as text,
itemKindColumn as text,
itemNameColumn as text,
isLeafColumn as text
) as table =>
let
tableType = Value.Type(table),
newTableType = Type.AddTableKey(tableType, keyColumns, true) meta
[
NavigationTable.NameColumn = nameColumn,
NavigationTable.DataColumn = dataColumn,
NavigationTable.ItemKindColumn = itemKindColumn,
Preview.DelayColumn = itemNameColumn,
NavigationTable.IsLeafColumn = isLeafColumn
],
navigationTable = Value.ReplaceType(table, newTableType)
in
navigationTable;
When executing above m query and using it as a connector in Power BI, i am only getting first page's 25 results, not getting second page data or any other page data.
There are total 474 pages.
Header -> "Link", showing next page and last page, when calling api using Postman
<https://demo.example.com/v4_6_release/apis/3.0/company/contacts?pageSize=25&page=2>; rel="next", <https://demo.example.com/v4_6_release/apis/3.0/company/contacts?pageSize=25&page=474>; rel="last"
I am not sure how to make it work and what's wrong, as I don't have much experience in M Query, any help is appreciated.
Upvotes: 1
Views: 1040
Reputation: 1061
Finally, I was able to implement paging in a different manner using List.Generate()
let
Expand= List.Generate(()=>
[Result= try GetData(1) otherwise null, Page = 1],
each [Result] <> null,
each [Result = try GetData([Page]+1) otherwise null, Page =[Page]+1],
each [Result]),
tableOfPages = Table.FromList(Expand, Splitter.SplitByNothing(), {"Column1"}),
ExpandAll= Table.ExpandTableColumn(tableOfPages, "Column1", {"id","firstName","lastName","company","site","title"})
in
ExpandAll;
Where GetData is
GetData = (page as number) =>
if page < 10 then
let
MainString= Text.Combine({"https://example.domain.com/v4_6_release/apis/3.0/company/contacts?page=",Number.ToText(page)}),
CompleteString=Text.Combine({MainString,"&fields=id,firstName,lastName,company,site,title"}),
Source = Json.Document(Web.Contents( CompleteString,
[ManualCredentials = true,
Headers = [#"Authorization" = Text.Combine({"Basic ", "Token"})]]))
in
Source
else null;
I have limited code to fetch for 10 pages only for testing purpose, but removing if-else condition from GetData will make it fetch all pages.
Upvotes: 2