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

Error running Flow #56

Closed Deepika1495 closed 3 years ago

Deepika1495 commented 3 years ago

I am having issues trying to run a Flow using run_flow_now method on TableauServerConnection.

This is my connection setup :

` tableau_server_config_2 = { 'myenv': { 'server': 'tableau server', 'api_version': '3.11', 'personal_access_token_name’:'token name', 'personal_access_token_secret’:'token', 'site_name':'', 'site_url':'' } }

conn_2 = TableauServerConnection(tableau_server_config_2, env='myenv') conn_2.sign_in() `

Running flow :

response = conn_2.run_flow_now( flow_id=‘<flow_id>' )

I am seeing the error :

{"error":{"summary":"Bad Request","detail":"Required request body is missing: public com.tableausoftware.api.rest.IRestApiResponse com.tableausoftware.api.rest.flows.RestApiFlowController.runFlowNow(com.tableausoftware.api.rest.util.RestApiVersion,com.tableausoftware.domain.user.IAuthenticatedUser,java.lang.String,com.tableausoftware.api.rest.viewmodels.TsRequest,java.lang.String,java.lang.String,javax.servlet.http.HttpServletResponse)","code":"400000"}}

I suspect the issue is because the request excepts an empty json instead of empty body.

I was able to reproduce on postman :

Screen Shot 2021-11-19 at 5 18 02 PM

With empty json on postman:

Screen Shot 2021-11-19 at 5 18 53 PM
divinorum-webb commented 3 years ago

Hi @Deepika1495 I have tried reproducing your error but my use of run_flow_now is indeed sending an empty JSON payload. In the code in this repository, if you view the TableauServerConnection method run_flow_now it can also be observed there that an empty JSON body request is defined.

Can you try running pip install -U tableau-api-lib to ensure you are not running an older version of the library?

You can verify that the connection has sent an empty JSON request by inspecting the active_request on your connection immediately after sending, like this:

print("active_request:", conn.active_request).

This is the output I see (I am triggering the default flow that has no output stages, so it errors out complaining about no output stage being configured):

active_request: {}
b'{"error":{"summary":"Bad Request","detail":"Output steps are required to run the flow.","code":"400142"}}'
Deepika1495 commented 3 years ago

Hi @divinorum-webb,

Thank you for taking a look. I am on the latest version and I did upgrade as well. Like you mentioned, print("active_request:", conn.active_request) is an empty json {}.

But I am still seeing the error

` response = conn_2.run_flow_now( flow_id='bab89e67-9d44-44ff-b82f-0d4147173a48' )

print(response.content)

b'{"error":{"summary":"Bad Request","detail":"Required request body is missing: public com.tableausoftware.api.rest.IRestApiResponse com.tableausoftware.api.rest.flows.RestApiFlowController.runFlowNow(com.tableausoftware.api.rest.util.RestApiVersion,com.tableausoftware.domain.user.IAuthenticatedUser,java.lang.String,com.tableausoftware.api.rest.viewmodels.TsRequest,java.lang.String,java.lang.String,javax.servlet.http.HttpServletResponse)","code":"400000"}}' `

Any idea what’s going on ? Maybe you can reproduce it on a valid flow ?

Deepika1495 commented 3 years ago

Hi @divinorum-webb ,

I think I may have found the issue, the headers are not being updated correctly for run_flow_now() method.

When I query the headers , I see this :

print("active_headers:", conn_2.active_headers)

active_headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'X-Tableau-Auth': ’token', 'content-type': 'multipart/mixed; boundary=a2e57a2181d3c4315ac4d3b5d196141f'} Before the run flow method, I publish a hyper extract file to the server and I think headers from that request gets added and not removed for the next request.

This is the publish request : response = conn_2.publish_data_source( datasource_file_path=PATH_TO_HYPER, datasource_name='athena publish python', project_id='d5e4fb67-e191-49da-a5f2-29663d7b1b75' )

I experimented with requests.post method directly and If I remove 'content-type': 'multipart/mixed; boundary=a2e57a2181d3c4315ac4d3b5d196141f’ from the headers, it works.

Error :

response = requests.post(
            url='https://tableau.com/api/3.12/sites/site-id/flows/flow-id/run',
            json={},
            headers={'Content-Type': 'application/json', 'Accept': 'application/json', 'X-Tableau-Auth': ’token', 'content-type': 'multipart/mixed; boundary=19d5bbf0af514ad62d925493ad69139b'},
            verify=True,
        )

print(response.text.encode('utf8’))

b'{"error":{"summary":"Bad Request","detail":"Required request body is missing: public com.tableausoftware.api.rest.IRestApiResponse com.tableausoftware.api.rest.flows.RestApiFlowController.runFlowNow(com.tableausoftware.api.rest.util.RestApiVersion,com.tableausoftware.domain.user.IAuthenticatedUser,java.lang.String,com.tableausoftware.api.rest.viewmodels.TsRequest,java.lang.String,java.lang.String,javax.servlet.http.HttpServletResponse)","code":"400000"}}’

Removing 'content-type': 'multipart/mixed; boundary=a2e57a2181d3c4315ac4d3b5d196141f’ from headers :

response = requests.post(
            url='https://tableau.com/api/3.12/sites/site-id/flows/flow-id/run',
            json={},
            headers={'Content-Type': 'application/json', 'Accept': 'application/json', 'X-Tableau-Auth': ’token'},
            verify=True,
        )

print(response.text.encode('utf8'))
b'{"job":{"runFlowJobType":{"flow":{"id”:”flow-id","name":"athena-extract-prep-extra-fields"},"flowRunId”:”flow-name"},"id":"e3732e98-6b14-4b51-8d2b-5c4256abf7ea","mode":"Asynchronous","type":"RunFlow","createdAt":"2021-11-20T16:27:22Z"}}’

The headers should be reset self.active_headers = self.default_headers before this https://github.com/divinorum-webb/tableau-api-lib/blob/667d7ccf30562fc8c37a8bb704014bb4262c30d7/src/tableau_api_lib/tableau_server_connection.py#L2973

divinorum-webb commented 3 years ago

Hi @Deepika1495 your conclusion is correct, the run_flow_now method should be resetting the connection's active headers to the default headers and this stage was missing. A patch has been made and if you run pip install -U tableau-api-lib you will install the latest version of the library containing the patch.

Thanks!