Skip to main content

Hi! I have asked a similar question like this before. I am trying to request an API token and use that token inside an API get. I do this because a token is only valid for 23 hours. I need to give the POST a few paramters: A client ID, Client Secret, grant type and a customer ID to identify who I am.

The API documentation says it uses OAUTH2.0 but I have not gotten it to work. I right now have the following code which returns the warning: 

The view "REST"."json" has no columns.The view is ignored

Below my code:

 

<api:script xmlns:api=http://apiscript.com/ns?v1 xmlns:xs=http://www.w3.org/2001/XMLSchema>
  <!-- See Column Definitions to specify column behavior and use XPaths to extract column values from JSON. -->
  <api:info title="API" desc="Generated schema file." xmlns:other=http://apiscript.com/ns?v1>
    <!-- You can modify the name, type, and column size here. -->
    <attr name="categoryName"   xs:type="string"    readonly="false"      other:xPath="/json/categoryName" />
    <attr name="created"        xs:type="date"      readonly="false"      other:xPath="/json/created"      />
    <attr name="closed"         xs:type="date"      readonly="false"      other:xPath="/json/closed"      />
    <attr name="description"    xs:type="string"    readonly="false"      other:xPath="/json/description"  />
 
  </api:info>
<api:set attr="urlbase" value="https://url.api.nl/" />
<api:set attr="http.url"  value="https://url.api.nl/token"/>
<api:set attr="http.header:name#1"  value="Accept"/>
<api:set attr="http.header:value#1"  value="application/x-www-form-urlencoded"/>
<api:set attr="http.contenttype"  value="application/x-www-form-urlencoded"/>
<api:set attr="http.postdata">
  {
      "client_id":"RANDOMID",
      "client_secret":"RANDOMID",
      "grant_type":"client_credentials",
      "CustomerId":"RANDOMID"
  }
</api:set>
 
<api:set attr="stopin.DataModel" value="DOCUMENT" />  
<api:set attr="stopin.JSONPath" value="$" />
<api:set attr="stopin.URITemplate" value="uurlbase]/apiurl" />
 
  <!-- The GET method corresponds to SELECT. Here you can override the default processing of the SELECT statement. The results of processing are pushed to the schema's output. See SELECT Execution for more information. -->
  <api:script method="GET">
    <!-- New API token is requested-->
    <api:call op="httpPost" in="http" out="login">
      <api:set attr="Token" value="dlogin.access_token]" />
      <!-- New API token is given to the STOPIN call-->
      <api:set attr="stopin.Header:Name#1" value="Authorization" />
      <api:set attr="stopin.Header:Value#1" value="cToken]" />
      <api:set attr="stopin.Header:Name#2" value="X-API-Key" />
      <api:set attr="stopin.Header:Value#2" value="RANDOMOD=" />
    </api:call>
    <api:set attr="stopin.URI" value="stopin.URITemplate]" />
          <api:call op="jsonproviderGet" in="stopin" out="stopout">
              <api:set attr="out.categoryName"  value=" stopout.categoryName]" />
              <api:set attr="out.created"       value=";stopout.created]" />
              <api:set attr="out.closed"        value="rstopout.closed]" />
              <api:set attr="out.description"   value="sstopout.description]" />
      <api:push item="out" />
    </api:call>
  </api:script>
</api:script>

 

Hi Robin

It looks correct, I am not that familiar with the httpPost operation. It seems like it is applied correctly.

How does it locate the RSD file you have here and is the file itself generating that “REST”.”json” table name?

Can you create a log verbosity level 3 and attach it here?


Sure, I have a log with verbosity lvl 5 if that is also okay:

 

2023-01-11T14:24:40.736+01:00    4    Connection: 1]    Executed connect: Success: (16 ms)
2023-01-11T14:24:40.736+01:00    1    0Connection: 1]    Opened REST connection. Version: 19.0.7354.0. Edition: 0ADO.NET Provider .NET 4.0].
2023-01-11T14:24:40.751+01:00    1    .Connection: 1]    Connection String: accesskey="";authscheme="NONE";autocache="False";backwardscompatibilitymode="False";cacheconnection="";cachelocation="%APPDATA%\CData\REST Data Provider";cachemetadata="False";cacheprovider="";cachetolerance="600";callbackurl="";catalog="CData";connectionlifetime="0";customheaders="";customurlparams="";datamodel="Document";datasource="";firewallpassword="";firewallport="";firewallserver="";firewalltype="NONE";firewalluser="";flattenarrays="";flattenobjects="True";format="JSON";generateschemafiles="OnUse";initiateoauth="OFF";jsonformat="JSON";kerberoskdc="";kerberoskeytabfile="";kerberosrealm="";kerberosservicekdc="";kerberosservicerealm="";kerberosspn="";kerberosticketcache="";location="C:\Users\sa-TimeXtender\Documents\TimeXtender Schema's\Fixi";logfile="C:\Users\sa-TimeXtender\Documents\TimeXtender Logs\Fixi API LOG\Fixi API LOG.txt";maxlogfilecount="";maxlogfilesize="100MB";maxrows="-1";oauthaccesstoken="";oauthaccesstokensecret="";oauthaccesstokenurl="*****";oauthauthorizationurl="";oauthclientid="";oauthclientsecret="";oauthgranttype="CODE";oauthparams="";oauthrefreshtoken="";oauthrefreshtokenurl="";oauthrequesttokenurl="";oauthsettingslocation="%APPDATA%\CData\REST Data Provider\OAuthSettings.txt";oauthverifier="";oauthversion="Disabled";offline="False";other="";poolidletimeout="";poolmaxsize="100";poolminsize="1";poolwaittime="";proxyauthscheme="NONE";proxyautodetect="True";proxyexceptions="";proxypassword="";proxyport="80";proxyserver="";proxyssltype="AUTO";proxyuser="";pseudocolumns="";readonly="False";region="NORTHERNVIRGINIA";rowscandepth="100";rtk="*****";schema="REST";secretkey="";sslclientcert="";sslclientcertpassword="";sslclientcertsubject="*";sslclientcerttype="";sslservercert="";supportenhancedsql="True";tables="";timeout="60";uri="";useconnectionpooling="False";useec2roles="False";verbosity="10";views="";xpath=""
2023-01-11T14:24:40.783+01:00    2    TConnection: 1]    Executing query: oRESET SCHEMA CACHE].
2023-01-11T14:24:40.798+01:00    1    0Connection: 1]    Executed query: 1RESET SCHEMA CACHE]. Success: (15 ms).
2023-01-11T14:24:40.814+01:00    5    )Connection: 1]    ADOConnectionImpl.GetTables(null)
2023-01-11T14:24:40.892+01:00    2    aConnection: 1]    Executing query: .SELECT * FROM sys_tablesviews].
2023-01-11T14:24:41.001+01:00    2    OConnection: 1]    Executing table schema query: +<NULL>].
2023-01-11T14:24:41.220+01:00    1    sConnection: 1]    Executed table schema query: Table: 2<NULL>], Success: 0 results (219 ms).
2023-01-11T14:24:41.220+01:00    2    UConnection: 1]    Executing view schema query: -<NULL>].
2023-01-11T14:24:41.220+01:00    1     Connection: 1]    Executed view schema query: <<NULL>], Success: 1 results (0 ms).
2023-01-11T14:24:41.251+01:00    5    sConnection: 1]    ADOConnectionImpl.GetColumns(null,'REST','json',null)
2023-01-11T14:24:41.251+01:00    2    nConnection: 1]    Executing query: uSELECT * FROM sys_tablecolumns  WHERE SchemaName LIKE @p1 AND TableName LIKE @p2].
2023-01-11T14:24:41.251+01:00    2     Connection: 1]    Parameter: p1 = REST, p2 = json
2023-01-11T14:24:41.283+01:00    2    :Connection: 1]    Executing column schema query: json].
2023-01-11T14:24:41.314+01:00    1    1Connection: 1]    Executed column schema query: json], Success: 4 results (31 ms).
2023-01-11T14:24:41.392+01:00    4    Connection: 1]    Executed sys_disconnect: Success: (16 ms)
2023-01-11T14:24:41.392+01:00    1    rConnection: 1]    Closed REST connection.


There does not seem to be any errors in that.

I think I would like to see you generate the error. Would you have time to do a remote session through teams tomorrow or similar?


Yes that would be great, I am available all afternoon after 1 PM CET (13:00)


Hi Robin
Good, I have sent an invite. We will talk then.


Hi Robin

I got some suggestions for you from CData.

Hi Thomas,

Regarding the handling of the token call, I see two major issues in the RSD file:

1) You seem to have defined the postdata as JSON. However, according to your postman screenshot, the token request body is composed of URL-encoded form-data. That is likely the reason for the HTTP 400 error. Instead of JSON, defining the post-data should resemble the below in API Script (the api:set for Data is one line):

<api:set attr="http.EncodePostData" value="false" />
<api:set attr="http.Data">client_id=RANDOMID&client_secret=RANDOMID&grant_type=client_credentials&CustomerId=RANDOMID</api:set>

2) Since the token endpoint's response is JSON, the access token needs to be parsed from the response body, which you will need jsonproviderGet for. So, op="httpPost" should be replaced with op="jsonproviderGet" in the first api:call. Just don't forget to add the following line before issuing the call for the token so that the correct HTTP method is used:

<api:set attr="method" value="POST" />

The RSD file aside, the postman requests mostly look like normal client_credentials grant OAuth to me (other than an extra parameter). Instead of using an RSD file to fetch the token, you should be able to set these properties to have the driver automate that part of the process:

AuthScheme --> OAuth
InitiateOAuth --> GETANDREFRESH
OAuthVersion --> 2.0
OAuthGrantType --> CLIENT
OAuthAccessTokenURL --> 
https://url.api.nl/token
OAuthClientId --> RANDOMID
OAuthClientSecret --> RANDOMID
OAuthParams --> CustomerId=RANDOMID

Please let me know if you have any questions about this.

Regards,
Garrett Bird

Do you see what you need to do?
It seems to me that you need to change the row where you state the PostData and httpPost needs to be changed, the suggested changes are in the response.

Regards
Thomas


Hi Thomas,

Thanks, i'll try it out!

Kind regards,

Robin


Hi Thomas,

I seem to get it to work quite a bit more using the answer from Cdata. However, I can’t seem to retrieve the access token from the post API. I have the following code:

 

<!-- Fixi Get -->
<api:script xmlns:api="http://apiscript.com/ns?v1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
  <!-- See Column Definitions to specify column behavior and use XPaths to extract column values from JSON. -->
  <api:info title="results" desc="Generated schema file." xmlns:other="http://apiscript.com/ns?v1">
    <!-- You can modify the name, type, and column size here. -->
    <attr name="id"                 xs:type="string"   readonly="false"              other:xPath="/json/results/id"                 />
    <attr name="categoryName"       xs:type="string"   readonly="false"              other:xPath="/json/results/categoryName"       />
    <attr name="closed"             xs:type="datetime" readonly="false"              other:xPath="/json/results/closed"             />
    <attr name="created"            xs:type="datetime" readonly="false"              other:xPath="/json/results/created"            />
    <attr name="description"        xs:type="string"   readonly="false"              other:xPath="/json/results/description"        />
  </api:info>
 
  <api:set attr="DataModel" value="DOCUMENT" />
  <api:set attr="JSONPath" value="$" />
  <api:set attr="urlbase" value="https://API.api.nl" />
  <api:set attr="http.url"  value="https://API.API.nl/token"/>
  <api:set attr="http.EncodePostData" value="false" />
  <api:set attr="http.Data">
    {
        "client_id":"ID",
        "client_secret":"ID",
        "grant_type":"client_credentials",
        "CustomerId":"ID"
    }
  </api:set>
 
  <api:set attr="stopin.DataModel" value="DOCUMENT" />
  <api:set attr="stopin.JSONPath" value="$.results" />
  <api:set attr="stopin.URI" value="surlbase]/paramters" />
 
  <!-- The GET method corresponds to SELECT. Here you can override the default processing of the SELECT statement. The results of processing are pushed to the schema's output. See SELECT Execution for more information. -->
  <api:script method="GET">
    <!-- New API token is requested-->
    <api:set attr="method" value="POST" />
    <api:call op="jsonproviderGet" in="http" out="login">
      <api:set attr="Token" value="klogin.access_token]" />
      <!-- New API token is given to the filein call-->
      <api:set attr="stopin.Header:Name#1" value="Authorization" />
      <api:set attr="stopin.Header:Value#1" value="aToken]" />
    </api:call>
    <api:set attr="stopin.URI" value="stopin.URITemplate]" />
          <api:call op="jsonproviderGet" in="stopin" out="stopout">
              <api:set attr="out.categoryName"  value="#stopout.categoryName]" />
              <api:set attr="out.created"       value="=stopout.created]" />
              <api:set attr="out.closed"        value="sstopout.closed]" />
              <api:set attr="out.description"   value=""stopout.description]" />
          <api:push item="out" />
    </api:call>
  </api:script>
</api:script>

Also: I get this error in the query tool:

 


Hi Robin

Good you came through. It seems like the authorization part is working, but you now have issues applying the token.
It seems to be this part that has something missing.

<api:set attr="Token" value="[login.access_token]" />

Specifically how access_token is described. I think you will need something like this.

<api:set attr="http.ElementMapPath#" value="/json/access_token" /><api:set attr="http.ElementMapName#" value="access_token" />

I am not sure where to add it, but I suppose it could be below the <api:set attr="http.Data"> </api:set>   tag.


Hi Thomas,

It seems to work with this weird solution:

I have filled in the Oauth fields in the data source options like Cdata described, this did not work. I then added the Client ID/Secret and stuff again in the OAuth Params field and it works! I have added a screenshot to show you what I mean. This is basically the result of a lucky guess, since I really couldn't get the RSD file to work even with the code provided. Thankfully this works very well too.

Data source settings

 


Hi Robin

That is good, this method is sometimes possible. It is not the case always. The benefit of using this, is that you don’t have to use RSD files at all.

If you do need to use an RSD file due to the need to do pagination or similar, you do not have to add any authorization to that, this setting will still be used to authorize it.

Regards
Thomas Lind


Reply