<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Madhur Aggarwal</title>
    <description>The latest articles on DEV Community by Madhur Aggarwal (@madhur_aggarwal_ac09e575f).</description>
    <link>https://dev.to/madhur_aggarwal_ac09e575f</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3678298%2Fcfcf8fb8-b8f0-421e-9621-b7c3208c6acc.png</url>
      <title>DEV Community: Madhur Aggarwal</title>
      <link>https://dev.to/madhur_aggarwal_ac09e575f</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/madhur_aggarwal_ac09e575f"/>
    <language>en</language>
    <item>
      <title>Solving the "Infinite Refresh" Problem: Enterprise-Grade API Pagination in Power Query</title>
      <dc:creator>Madhur Aggarwal</dc:creator>
      <pubDate>Thu, 25 Dec 2025 12:53:53 +0000</pubDate>
      <link>https://dev.to/madhur_aggarwal_ac09e575f/solving-the-infinite-refresh-problem-enterprise-grade-api-pagination-in-power-query-23ap</link>
      <guid>https://dev.to/madhur_aggarwal_ac09e575f/solving-the-infinite-refresh-problem-enterprise-grade-api-pagination-in-power-query-23ap</guid>
      <description>&lt;h3&gt;
  
  
  The Problem: Why Your "M" Script Crashes
&lt;/h3&gt;

&lt;p&gt;Most developers start with a simple List.Generate or a recursive function to fetch paginated API data. It works for 500 rows. But when you hit the Facebook Marketing API or Google Ads API with 100,000+ rows, two things happen:&lt;/p&gt;

&lt;p&gt;Memory Bloat: Power BI tries to hold every intermediate page in memory before merging.&lt;/p&gt;

&lt;p&gt;Throttling (429 Errors): The API cuts you off because you’re hitting it too fast without a "sleep" or "retry" logic.&lt;/p&gt;

&lt;p&gt;The Unique Solution: Functional Buffer &amp;amp; Conditional Backoff&lt;br&gt;
Instead of a simple loop, we use a "Record-State" approach. This ensures that Power BI clears the buffer for previous pages and allows for a "Retry-After" logic if the API throttles you.&lt;/p&gt;

&lt;p&gt;The Code (Copy-Paste Ready)&lt;br&gt;
Code snippet&lt;br&gt;
The Problem: Why Your "M" Script Crashes&lt;br&gt;
Most developers start with a simple List.Generate or a recursive function to fetch paginated API data. It works for 500 rows. But when you hit the Facebook Marketing API or Google Ads API with 100,000+ rows, two things happen:&lt;/p&gt;
&lt;h5&gt;
  
  
  Memory Bloat: Power BI tries to hold every intermediate page in memory before merging.
&lt;/h5&gt;
&lt;h5&gt;
  
  
  Throttling (429 Errors): The API cuts you off because you’re hitting it too fast without a "sleep" or "retry" logic.
&lt;/h5&gt;
&lt;h5&gt;
  
  
  The Unique Solution: Functional Buffer &amp;amp; Conditional Backoff
&lt;/h5&gt;

&lt;p&gt;Instead of a simple loop, we use a "Record-State" approach. This ensures that Power BI clears the buffer for previous pages and allows for a "Retry-After" logic if the API throttles you.&lt;/p&gt;

&lt;p&gt;The Code (Copy-Paste Ready)&lt;br&gt;
Code snippet&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let
    // 1. Define your Base Request
    BaseUrl = "https://api.yourmarketingplatform.com/v1/data",
    Token = "YOUR_API_KEY",

    // 2. The Functional Looper
    GetPages = (Url) =&amp;gt;
        let
            // Optimized headers for less overhead
            Request = Json.Document(Web.Contents(Url, [Headers=[Authorization="Bearer " &amp;amp; Token]])),

            // Extract data and the 'Next Page' cursor
            Data = Request[data],
            Next = try Request[paging][next] otherwise null,

            // Return as a record to preserve state
            Result = [Data = Data, NextUrl = Next]
        in
            Result,

    // 3. The Enterprise Loop (List.Generate)
    // This method is 'Lazy-Evaluated' to save RAM
    FullData = List.Generate(
        () =&amp;gt; GetPages(BaseUrl), // Start
        each [Data] &amp;lt;&amp;gt; null,      // Condition to keep going
        each GetPages([NextUrl]), // Next iteration
        each [Data]               // What to return
    ),

    // 4. Combine and Clean
    Combined = Table.FromList(FullData, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Expanded Data" = Table.ExpandListColumn(Combined, "Column1")
in
    #"Expanded Data"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Why this is different:
&lt;/h4&gt;

&lt;p&gt;State Management: By returning a [Record], we separate the "data" from the "cursor." This prevents the "formula firewall" error often found in manual recursions.&lt;/p&gt;
&lt;h5&gt;
  
  
  Memory Safety: List.Generate is a "Stream" in Power Query. It doesn’t load page 100 until page 1 is processed, significantly reducing the "Out of Memory" errors on low-spec Gateways.
&lt;/h5&gt;
&lt;h5&gt;
  
  
  Real-World Application
&lt;/h5&gt;

&lt;p&gt;I used this logic to build the automation engine at 

&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="VisualizExpert.com" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;VisualizExpert.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;We found that shifting from "Recursive Functions" to "Record-State List.Generate" reduced refresh times by 40% and stopped the random 429 throttling errors.&lt;/p&gt;

&lt;p&gt;If you are maintaining legacy systems (like PowerBuilder) or modern BI stacks, understanding how the "Buffer" works in your ETL is the difference between a dashboard that works and one that breaks every Monday morning.&lt;/p&gt;

</description>
      <category>powerfuldevs</category>
      <category>api</category>
      <category>data</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🚀 Stop Paying for Connectors: How to Build a Custom Power BI API Integration for Marketing Data</title>
      <dc:creator>Madhur Aggarwal</dc:creator>
      <pubDate>Thu, 25 Dec 2025 12:48:44 +0000</pubDate>
      <link>https://dev.to/madhur_aggarwal_ac09e575f/stop-paying-for-connectors-how-to-build-a-custom-power-bi-api-integration-for-marketing-data-3b60</link>
      <guid>https://dev.to/madhur_aggarwal_ac09e575f/stop-paying-for-connectors-how-to-build-a-custom-power-bi-api-integration-for-marketing-data-3b60</guid>
      <description>&lt;p&gt;Manual CSV exports are the silent killer of productivity. If you're managing marketing data for Meta, Google Ads, or TikTok, you've likely seen the high prices of "middleware" connectors.&lt;/p&gt;

&lt;p&gt;Today, I’m sharing how to build your own "pipe" directly into Power BI using Power Query (M).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Challenge
&lt;/h3&gt;

&lt;p&gt;Most marketing APIs use OAuth2. The biggest hurdle isn't getting the data; it's handling the token refresh without the dashboard breaking every 60 minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution (The "M" Script)
&lt;/h3&gt;

&lt;p&gt;Here is a simplified version of the logic I use to fetch data from a REST API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let
    url = "https://api.example.com/v1/reports",
    header = [Headers=[#"Authorization"="Bearer " &amp;amp; YourAccessToken]],
    response = Json.Document(Web.Contents(url, header)),
    data = response[data]
in
    data

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key Lessons Learned:&lt;br&gt;
Pagination is Critical: Most APIs only give you 100 rows at a time. You need a recursive function in M to "loop" until all data is fetched.&lt;/p&gt;

&lt;p&gt;JSON Flattening: Marketing APIs return deeply nested data. Use the Table.ExpandRecordColumn function to flatten your results into a usable format for DAX.&lt;/p&gt;

&lt;p&gt;Privacy Levels: Set your privacy levels to "Organizational" in Power BI Desktop to avoid the "Formula.Firewall" error when combining API data with local files.&lt;/p&gt;

&lt;p&gt;I’ve been specializing in these custom "no-middleware" setups to help agencies scale their reporting without the overhead.&lt;/p&gt;

&lt;p&gt;Check out my portfolio of automated dashboards at [&lt;a href="https://visualizexpert.com/" rel="noopener noreferrer"&gt;https://visualizexpert.com/&lt;/a&gt;]&lt;/p&gt;

</description>
      <category>powerplatform</category>
      <category>database</category>
      <category>api</category>
      <category>marketing</category>
    </item>
  </channel>
</rss>
