Forum Discussion
Trouble scraping SharePoint Version History
- 6 months ago
Hi ,To fix your refresh issues and answer your question on "Why the List API," here is the technical breakdown and the code solution.
1. The "Dynamic Data Source" Fix
You are getting the refresh error because Power BI Service cannot authenticate a data source where the URL is built inside the query (e.g., combining a base URL with a file ID). The Service needs to know the Root URL statically before the query runs.
To fix this, you must use the
RelativePath andQuery options insideWeb.Contents. This allows you to keep the main URL static (satisfying the gateway/refresh) while making the rest dynamic.The Incorrect Way (Causes Dynamic Error):
Web.Contents("https://site.com/api/files/" & FileID)The Correct Way (Refreshable):
Web.Contents("https://site.com", [RelativePath="api/files/" & FileID])2. Why List API vs. Folder API?
You asked why the List API is more accurate.
-
Folder API (
GetFolderBy...): This is a file-system abstraction. When you ask for version history here, SharePoint often relies on a cached view of the file metadata to save performance. If that cache is stale (which happens often with deep metadata like versions), you get gaps until you "nudge" the file. -
List API (
.../items): This queries the actual underlying SharePoint database table (All Documents are just items in a List). It bypasses the "folder view" abstraction and hits the transactional data directly. This is whyMurtaza_Ghafoor recommended it.3. The Solution Code
Here is how to combine the List API (for accuracy) with RelativePath (for refresh stability). This query gets all files and their versions in one go without the dynamic error.
let // 1. Define your Static Base URL (The part you authenticate against) BaseUrl = "https://[YOUR_TENANT].sharepoint.com/sites/Tracking", // 2. Use RelativePath to hit the List API. // We use the List Endpoint because it is the database source of truth. Source = Json.Document(Web.Contents(BaseUrl, [ RelativePath = "_api/web/lists/getbytitle('Documents')/items", Query = [ // We expand File and Versions immediately to avoid N+1 query loops #"$expand" = "File,File/Versions,File/Versions/CreatedBy", // Select only what you need to keep it fast #"$select" = "File/Name,File/ServerRelativeUrl" ], Headers = [Accept="application/json;odata=verbose"] ])), // 3. Standard JSON navigation from here d = Source[d], results = d[results], #"Converted to Table" = Table.FromList(results, Splitter.SplitByNothing(), null, null, ExtraValues.Error), #"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"File"}, {"File"}), // 4. Expand the Versions nested inside the File record #"Expanded File" = Table.ExpandRecordColumn(#"Expanded Column1", "File", {"Name", "ServerRelativeUrl", "Versions"}, {"FileName", "FileUrl", "Versions"}), #"Expanded Versions" = Table.ExpandRecordColumn(#"Expanded File", "Versions", {"results"}, {"VersionResults"}), #"Expanded VersionResults" = Table.ExpandListColumn(#"Expanded Versions", "VersionResults"), // 5. Expand Version Details #"Expanded Version Details" = Table.ExpandRecordColumn(#"Expanded VersionResults", "VersionResults", {"VersionLabel", "Created", "CreatedBy"}, {"VersionLabel", "VersionCreated", "CreatedByRecord"}), #"Expanded CreatedBy" = Table.ExpandRecordColumn(#"Expanded Version Details", "CreatedByRecord", {"Title", "Email"}, {"User", "UserEmail"}) in #"Expanded CreatedBy"Key changes for your setup:
-
Change
BaseUrl to your site root. -
If your library is not named "Documents", change
getbytitle('Documents') to your library name. -
This avoids the "Dynamic Data Source" error because
BaseUrl is a static text string.Check out my blog for more on optimizing these calls if the list is very large!
This response was assisted by AI for translation and formatting purposes.
-
-
-
-
-
Hi electrichead,
Thank you for reaching out to Microsoft Fabric Community.
This is expected behaviour with the SharePoint REST API and not an issue with power query or refresh. Refreshing power query does not change this because the incomplete data is coming directly from SharePoint.
If you need consistent and complete version history, versions must be queried per file, like for example:
GetFileByServerRelativeUrl('<file>')/Versions?$expand=CreatedBy
List the files first and then call the versions endpoint for each file. That is the only proper way for auditing version history.
Thanks and regards,
Anjan Kumar Chippa
Thank you, although I don't fully understand why this is expected I can accept it for what it is (if you have a reference you can point me to so I understand better please do! I'm assuming this is to save memory/processing power? Not sure why else to limit data).
I've tried using the method you recommended to query the file instead of the file location, using the bit of code you supplied. Unfortunately I now run into the issue of the published file not being able to be refreshed because of dynamic data sources. Essentially, within the query I can build a list of the files I need the version history of and then extract it, but because this list is built within the query it is dynamic. Do you have a suggestion on how to work around this? I do need to run daily refreshes.
- vojtechsima6 months agoSuper User
Hey man, electrichead ;
The issue with the dynamic source is an easy fix. Split your WebContents url into base part and RelativePath, like this: Web.Contents( "https://yourtenant.sharepoint.com", [RelativePath="theOtherPartsHere"]).
Check out my blog for a detailed way to get files the fastest way from SharePoint. Scroll to the last example.
https://www.vojtechsima.com/post/fix-slow-refreshes-faster-way-to-load-sharepoint-files-in-power-bi