Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

July 28 - August 9 | Final Round of the Power BI Dataviz World Championships. This is your chance. Learn more

Reply
helspaul
Frequent Visitor

API pagination which will work on Power BI Service

I'm trying to call paginated API data, publish that PBIX to the Power BI Service and have it still work. I found this site How to Handle API Pagination in Power BI - Syntera, tested the example code and it works. 

 

I then tried to alter it to my site and hit a bit of an issue. This is the code i've got

 

let
// Recursive function to call a api based on the initial parameters
FetchData = (query as nullable record) as list =>
let
// Calling the web service with the fixed parameters for headers and relative path while adding the variable query data
Source = Json.Document(Web.Contents(url, [Headers = headers, RelativePath = relative_path, Query = query])),
// Store the retrieved results
data = try Source[tasklists] otherwise {},
// Try to get the next link if it is present and extract the page number
next_page = try Text.Split(Text.Split(Source[next], "?page="){1}, "&"){0} otherwise null,
// if there is a next link, the function calls itself again with the new query parameters to get the next page
next_result = if next_page <> null then @FetchData([page = next_page]) else {}
in
// Combine current page data with next page data to a list
List.Combine({data, next_result}),

url = "https://xxxxxxxxxxxx.teamwork.com/projects/api/v3", 
relative_path = "tasklists.json?pagesize=50",
query = [], 
headers = [], 

// Call the recursive function starting from the base url
results = FetchData(query),
#"Converted to Table" = Table.FromList(results, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
in
#"Converted to Table"

 

On the API used in the demo the next page logic relies on the next page URL being delivered as part of the response

helspaul_0-1761923929445.png

But my site does not have this. Here is an example of a blank response. Tasklists usually carries the content I want to append when I call the earlier pages. 

helspaul_1-1761924076332.png

 

I've tried multiple ways to increase the page number by i +1.

I've also tried to test whether tasklists is null to end my query, or access "HasMore" to find out when its false and end my query. None have worked

 

Anyone able to explain how I can make this call a series of pages, and stop when the content stops?

 

Thanks

Paul

 

 

  

1 ACCEPTED SOLUTION
vojtechsima
Super User
Super User

Hey, @helspaul 

first of all, split the url, so that the it's only uptil the teamwork.com part, the rest should be inside RelatiVEpath.



Every API can handle pagination differently, I built most common approaches and how to deal with them here:

Your approach is similar to the JIRA Offset I wrote about, feel free to check it out, I put a snippet from there here for quicker access:
 
populatePagesLG = List.Generate(
()=> 0,
(page) => page <= totalPages,
(page) => page + 1,
(page) => request(page * pageSize, pageSize)
),
 
Before that tho, built pages:

request = (offset as number, limit as number) =>  
    Json.Document(  
        Web.Contents(  
        [  
            RelativePath="/rest/api/3/search?jql=project=BI",  
            Query =  
                [  
                    startAt=Text.From(offset),  
                    maxResults=Text.From(limit)  
                ],  
            Headers=  
                [  
                    Authorization=basic_auth_string  
                ]  
        ]  
        )  
    )  
getTotal = request(0, 0)[total]
pageSize = 100
totalPages = Number.RoundDown( getTotal / pageSize )
 





Any kudos or recognition appreciated. To learn more on the topic, check out my blog and follow me on LinkedIn.

View solution in original post

4 REPLIES 4
v-tejrama
Community Support
Community Support

Hi @helspaul ,

 

Thank you @vojtechsima  for the response provided!


Has your issue been resolved? If the response provided by the community member addressed your query, could you please confirm? It helps us ensure that the solutions provided are effective and beneficial for everyone.


Thank you for your understanding!

vojtechsima
Super User
Super User

Hey, @helspaul 

first of all, split the url, so that the it's only uptil the teamwork.com part, the rest should be inside RelatiVEpath.



Every API can handle pagination differently, I built most common approaches and how to deal with them here:

Your approach is similar to the JIRA Offset I wrote about, feel free to check it out, I put a snippet from there here for quicker access:
 
populatePagesLG = List.Generate(
()=> 0,
(page) => page <= totalPages,
(page) => page + 1,
(page) => request(page * pageSize, pageSize)
),
 
Before that tho, built pages:

request = (offset as number, limit as number) =>  
    Json.Document(  
        Web.Contents(  
        [  
            RelativePath="/rest/api/3/search?jql=project=BI",  
            Query =  
                [  
                    startAt=Text.From(offset),  
                    maxResults=Text.From(limit)  
                ],  
            Headers=  
                [  
                    Authorization=basic_auth_string  
                ]  
        ]  
        )  
    )  
getTotal = request(0, 0)[total]
pageSize = 100
totalPages = Number.RoundDown( getTotal / pageSize )
 





Any kudos or recognition appreciated. To learn more on the topic, check out my blog and follow me on LinkedIn.

Hi, thanks for your response. I've followed the post on your website and tailored it to the API i'm trying to call. Most importantly it still refreshes in the online Power BI Service

 

This is what I finalised on

 

let
request = (page as number, pageSize as number) =>
Json.Document(
Web.Contents(
"https://xxxxxxxxxxxx.teamwork.com/",
[
RelativePath="/projects/api/v3/tasklists.json",
Query =
[
page=Text.From(page),
pageSize=Text.From(pageSize)
]
]
)
),
getTotal = request(1, 50)[meta][page][count],
pageSize = 50,
totalPages = Number.RoundUp( getTotal / pageSize ),
manualPages = {1..totalPages},
populatePages = List.Transform( manualPages, each request(_, pageSize)[tasklists]),
expandPages = List.Combine(populatePages),
#"Converted to Table" = Table.FromList(expandPages, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
in
#"Converted to Table"

 

Thanks

 

@helspaul , nice good job, looks good.






Any kudos or recognition appreciated. To learn more on the topic, check out my blog and follow me on LinkedIn.

Helpful resources

Announcements
FabCon and SQLCon Barcelona 2026

FabCon & SQLCon – Barcelona 2026

Join us in Barcelona for FabCon and SQLCon, the Fabric, Power BI, SQL, and AI community event. Save €200 with code FABCMTY200.

Fabric Community Sticker Design Challenge Barcelona Carousel

Fabric Community Sticker Challenge - Barcelona 2026

If you love stickers, then you will definitely want to check out our community sticker challenge, Barcelona edition!

July Power BI Update Carousel

Power BI Monthly Update - July 2026

Check out the July 2026 Power BI update to learn about new features.

Power BI DataViz World Championships carousel

Power BI DataViz World Championships - June 2026

A new Power BI DataViz World Championship is coming this June! Don't miss out on submitting your entry.

Top Solution Authors