5

I am working with a cloud-based service that is exposed using OAuth REST API.

I have a working Python script, with which I am able to first post username, password and api token to get an authentication token. Then I use the api and authentication tokens to get data. Here is my Python script:

import requests

base_url = 'https://example.com'
user_name = 'john_doe'
password = 'pssw0rd'
api_token = '4r-eueyta-dh7cuq-26'
timeout_min = 1

headers = {'Accept': 'application/json'}

# get authentication token
auth_url = base_url + '/api/authenticate'
data = {'Username': user_name, 
        'Password': password, 
        'ApiToken': api_token, 
        'AuthorizationTokenTimeoutMinutes': timeout_min}
r = requests.post(auth_url, headers=headers, data=data)
# the entire string response is the auth token
auth_token = r.text

# get data
proj_url = base_url + '/api/project/active?' + \
             'api-token={0}&authentication-token={1}'.format(api_token, auth_token)
r = requests.get(proj_url, headers=headers)
print(r.text)

This is working fine.


Next I want to use the same approach inside Microsoft Power BI to configure this data as a data source. I followed the approach outlined at http://angryanalyticsblog.azurewebsites.net/index.php/2016/05/16/api-strategies-with-power-bi/

As mentioned in the post, I set the variables

  • base_url
  • user_name
  • password
  • api_token
  • auth_token_timeout_min

as parameters and set their values. Then got the following power query script in advanced editor:

 let
 // get auth token
 auth_url = #"base_url" & "/api/authenticate",
 post_data = "Username=" & #"user_name" & "&Password=" & #"password" & "&ApiToken=" & #"api_token" & "&AuthorizationTokenTimeoutMinutes=" & #"auth_token_timeout_min",
 AuthJsonQuery = Web.Contents(auth_url,
                              [Headers = [#"Accept"="application/json"], 
                               Content = Text.ToBinary(post_data)]),
 auth_token = Json.Document(AuthJsonQuery),

 // get data
 proj_url = #"base_url" & "/api/project/active?api-token=" & #"api_token" & "&authentication-token=" & auth_token,
 GetJsonQuery = Web.Contents(proj_url,
                             [Headers = [#"Accept"="application/json"]]),
 FormatAsJsonQuery = Json.Document(GetJsonQuery),
  in
  #"FormatAsJsonQuery"

This script gives the following error:

DataSource.Error: Web.Contents failed to get contents from 'https://example.com/api/authenticate' (415): Unsupported Media Type
Details:
    DataSourceKind=Web
    DataSourcePath=https://example.com/api/authenticate
    Url=https://example.com/api/authenticate

The raw response from the first POST request is exactly the authentication token and I am missing something in correctly decoding it.

If I manually configure the authentication token directly in proj_url then I am able to get the data, so I am doing something wrong with getting the authentication token.


UPDATE: My goal was to somehow make the data available inside Power BI. I took an alternative approach with using R as a data source. (You will need to install R and the httr package in R for this.) Posting that solution here:

library(httr)

base_url <- 'https://example.com'
user_name <- 'john_doe'
password <- 'pwws0rd'
api_token <- '4r-eueyta-dh7cuq-26'
timeout_min <- 1

# get authentication token
auth_url <- paste0(base_url, '/api/authenticate')
data <- list('Username' = user_name,
             'Password' = password,
             'ApiToken' = api_token,
             'AuthorizationTokenTimeoutMinutes' = timeout_min)
resp <- POST(auth_url,
             body = data, 
             encode = 'json')
auth_token <- content(resp, "parsed", "application/json")

# get data
proj_url <- paste0(base_url, '/api/project/active?', 
                   'api-token=', api_token, 
                   '&authentication-token=', auth_token)
resp <- GET(proj_url, encode = 'json')

# convert the response to data frame
results <- content(resp, "parsed", "application/json")
results <- lapply(results, function(x) {
                    x[sapply(x, is.null)] <- NA
                    unlist(x)})
projects <- do.call("rbind", results) # matrix
projects <- data.frame(projects, stringsAsFactors = FALSE)

projects is then available for importing into Power BI.

arun
  • 10,685
  • 6
  • 59
  • 81
  • What happen if you remove the code from line `proj_url` till the end and end it with `in auth_token`? Is it still the same error? – Foxan Ng Mar 19 '17 at 16:30
  • Just a guess: The format of the "auth_token"-step needs to be in text-format. You can force it like this: auth_token = Text.From(Json.Document(AuthJsonQuery)), – ImkeF Mar 20 '17 at 07:01
  • @ImkeF: still same error – arun Mar 20 '17 at 18:55
  • @FoxanNg: I do not understand. What should I remove from `proj_url`? Thx. – arun Mar 20 '17 at 18:56
  • Is this auth2 authentication? maybe you shouldn't use the username and password in powerquery script. You may call the api and in power bi basic authentication add the user and password for the complete url. Remember you can user R script or Python script as a connect to get data (in case you can't solve it) – ibarrau Aug 05 '19 at 17:20

1 Answers1

1

I know it is too late to answer, but I'm guessing it is because the header lacks "Content-Type=application/x-www-form-urlencoded".

Python requests library automatically adds this header part, while Power Query does not.

Kosuke Sakai
  • 2,336
  • 2
  • 5
  • 12