divinorum-webb / tableau-api-lib

An API library that allows developers to call on the methods listed in Tableau's REST API documentation.
MIT License
96 stars 34 forks source link

query_projects() is limited to pageSize=100 and pageNumber=1 #116

Closed julienmariethoz closed 1 year ago

julienmariethoz commented 1 year ago
response = conn.query_projects(parameter_dict=params)
print(response.request.path_url)

'/api/3.17/sites/site-id/projects'

I would like to change default value using parameter_dict https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#query_projects

params = {}
params["pageSize"]="1000"
print(params) #{'pageSize': '1000'}
response = conn.query_projects(parameter_dict=params)
print(response.request.path_url)

'/api/3.17/sites/site-id/projects?1000'

while the url with parameters should be

'/api/3.17/sites/site-id/projects?pageSize=1000

If I try with the pageNumber parameter

params = {}
params["pageSize"]="1000"
params["pageNumber"]="1"
print(params) #{'pageSize': '1000', 'pageNumber': '1'}
response = conn.query_projects(parameter_dict=params)
print(response.request.path_url)

'/api/3.17/sites/site-id/projects?1000&1'

while the url with parameters should be

'/api/3.17/sites/site-id/projects?pageSize=1000&pageNumber=1

The keys are not part of the url and are never send to the server

divinorum-webb commented 1 year ago

Hey @julienmariethoz this is actually by design, as odd as it may seem. The reason being primarily to decouple the nuances of how Tableau's REST API implements filtering from any assumptions the tableau-api-lib library would make in combining the key/value pairs defining your URL parameters.

You could achieve what you want by having your parameters look like this: {"page_size": "pageSize=1000", "page_number": "pageNumber=1"}

One problem with assuming the key/value pairs work in the way you have suggested is that when passing URL parameters which set filter or parameter values (interacting with actual filters and parameters in your worksheets), these behave fundamentally differently from the built-in URL parameters for pagination. Because the Tableau REST API has different classes of filters, parameters, and native URL parameters (pagination) which all may be relevant to any given query, the existing implementation was used for tableau-api-lib to offer a generalized approach for defining whichever parameter is needed.

For example, consider these custom parameters used in my article on filtering:

CUSTOM_PARAMS = {
    'region': 'vf_Region=East,West',
    'ship_mode': 'vf_Ship Mode=First Class,Standard Class',
    'param': 'vf_Superstore Sales | Column Parameter=Segment'
}

The values look a bit odd, containing the prefix "vf" before each filter expression. This is a nuance of how Tableau implements the filtering in the REST API. A judgment call was made that it would be overall less confusing if the user could look up how filters work in Tableau's REST API and then define the "value" in their key/value pairs to implement any given filter expression directly. You'll notice that when you set the pagination parameters such as pageSize and pageNumber, you do not prefix the expression with "vf".

In other words, the "key" is arbitrary and only used for you (the developer) to keep track of your filters. The "value" is the full URL parameter expression.

If the implementation were instead as you suggest, then the above parameters would look like this:

CUSTOM_PARAMS = {
    'vf_Region=': 'East,West',
    'vf_Ship Mode=': 'First Class,Standard Class',
    'vf_Superstore Sales | Column Parameter=': 'Segment'
}

In the end I believe splitting the URL parameter expression across key/value pairs is more confusing than the existing implementation. That said, I understand that this is my opinion and others may disagree. Hope this helps!

julienmariethoz commented 1 year ago

Great explanation. Thank you for the very reactive reply. Maybe you can add the link to your medium article in the readme of this project.