Handling Multiple URL Query Parameters With The Same Name Using Web.Contents In Power Query/Power BI

Some time ago I wrote a pair of popular posts about using the Query and RelativePath options of the Web.Contents function in Power Query and why they are important for dataset refresh. I have recently learned something extra about this subject which merits a new post, though: how to handle multiple URL query parameters with the same name.

In the examples for this post I’ll be using a free, fake web service available at http://jsonplaceholder.typicode.com/ which requires no authentication so you will be able to run the code I show yourself. Let’s start by considering the following call to the comments resource of this API:


In M, you can use the Web.Contents function and the Query option to call the API like so:

//Generates the URL http://jsonplaceholder.typicode.com/comments?postId=1

Now this API – unlike many others – allows you to pass multiple URL query parameters of the same name. For example this is a valid call:


The problem is, if you try to do the following in M:


…you’ll get an error, because the Query option take a record and a record can’t have two fields with the same name.

Here’s where it gets interesting. In the working example above, the postId field in the Query record contains a text value. The field can contain a list of text values instead, though, and this is how you solve the problem:

//Generates the URL http://jsonplaceholder.typicode.com/comments?postId=1&postId=2

This results in a URL with two query parameters that are both called postId but have the values 1 and 2 respectively.

There’s something else worth mentioning about this too. Sometimes when you’re generating a URL you may not want to add a query parameter to it if a value is null. One way of handling this is to start with an empty record and then add fields to it using the Record.AddField function, but using an empty list provides another approach. For example:

//Generates the URL http://jsonplaceholder.typicode.com/comments
//and *not* http://jsonplaceholder.typicode.com/comments?postId=

…generates a URL without the postId query parameter in. This means you can write a simple function with an optional parameter for postId like this:

(optional myPostId as text) =>
    Web.Contents("http://jsonplaceholder.typicode.com/comments",[Query=[postId=myPostId ?? {}]])

If a text value is passed to myPostId then the postId query parameter is added to the URL; if no value is passed, myPostId is null and the ?? null coalescing operator (see Ben Gribaudo’s post here for more information on this operator) can be used to replace it with an empty list.

One last thing to mention: if you need to see the web service calls generated by Web.Contents when you’re testing in the Power Query Editor, you can use the query diagnostics functionality as I show here.

[I’m extremely grateful to Dave Maiden for letting me know about all this – it answers a question I have been asked several times in the past]

8 responses

  1. Pingback: Handling “Duplicate” Query String Values with Power Query – Curated SQL

  2. Pingback: Web.Contents: Using Dynamic and Duplicate key names in a Query – Ninmonkey

  3. That’s neat. I solved it by generating `options[RelativePath]` using [Uri.EscapeDataString](https://docs.microsoft.com/en-us/powerquery-m/uri-escapedatastring)


    Have you seen docs or information on how `Query` behaves for this function or other data sources, like parameterized SQL queries? The [pingback](https://curatedsql.com/2021/01/11/handling-duplicate-query-string-values-with-power-query/) says he found different results depending on the environment.

  4. Pingback: Chris Webb's BI Blog: Using The RelativePath And Query Options With Web.Contents() In Power Query And Power BI M Code Chris Webb's BI Blog

  5. Hi Chris, thank you for this information! I am trying to replicate the RelativePath soultion to my dynamic data source which uses the following REST API:
    Json.Document(Web.Contents(“https://api-au.myconnectwise.net/v4_6_release/apis/3.0/sales/opportunities?pagesize=1000&conditions=locationId in (32)”, [Headers=[Authorization=”Basic Sxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==”, Clientid=”dxxxxxxxxxxxxxxxxxxxxxxxxxxxx0″]]))

    This gives me a list which I further transform into tables. Not sure how to get the condition part in Query [].
    I have come to following reformatting so far:
    Source = Json.Document(
    RelativePath = “v4_6_release/apis/3.0/sales/opportunities”,
    Query = [pagesize = 1000
    & locationId = {“32”}]
    Headers = [
    Authorization = “Basic Sxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==”,
    Clientid = “dxxxxxxxxxxxxxxxxxxxxxxxxxxxx0”

    Error returned:
    “Expression.Error: The name ‘locationId’ wasn’t recognized. Make sure it’s spelled correctly.”

    Could really use your help as I am just stepping in the M query universe!
    Thank you!

  6. Thank you so much for the info! I have a question. How can you solve a in the relative path, a query parameter that incluye a M function:

    This is the normal url –> Source = Json.Document(Web.Contents(“https://mycompany.pipedrive.com/v1/notes?limit=500&pinned_to_person_flag=0&api_token=12345abcde&start=”&Number.ToText(Page))),

    This is the relative path source that is not working (because of the NumberToText) –> Source = Json.Document(Web.Contents(“https://mycompany.pipedrive.com/v1/notes”, [Query=[api_token=”03a31747879be86fe4350e0aa439b7c231396109″, limit=”500″, pinned_to_person_flag=”0″, start=”Number.ToText(Page)]])),

Leave a Reply to poojashriwastav Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: