WinBatch® Technical Support Forum

All Things WinBatch => WinBatch => Topic started by: hdsouza on November 18, 2017, 05:15:00 PM

Title: Sending an API-Key
Post by: hdsouza on November 18, 2017, 05:15:00 PM
Hi ,
I am trying to write a script that can pass  API credentials.
As an example i want to get the available cash  as in https://www.lendingclub.com/developers/available-cash (https://www.lendingclub.com/developers/available-cash)
This is my first time writing calls to JSON, so I am a little lost.

Here is what I wrote so far , but it returns a bad response.
Any help would be appreciated.

Code (winbatch) Select

Invest_ID = "5166XXX"
cURL = 'https://api.lendingclub.com/api/investor/v1/accounts/%Invest_ID%/availablecash'
apikey = 'GVsZuDKATPRlsajFiBXXXXXXX'
GoSub UDFs

oHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
a = oHTTP.Open("GET", cURL, @FALSE)
;----------------------------------------------------------------------------
; Define Headers
;----------------------------------------------------------------------------
str_64=Base64StringFromClearString(B64GetCookie(),StrCat(":",apikey))
oHTTP.SetRequestHeader("Authorization",StrCat("Basic ", str_64))
oHTTP.SetRequestHeader("Content-Type", "application/json"); Content-Type

;----------------------------------------------------------------------------
; Send the request
;----------------------------------------------------------------------------
oHTTP.Send()
oHTTP.WaitForResponse()

If oHTTP.Status != 200
   If oHTTP.Status == 302
      Pause( "Server Attempted Redirect to: ", oHTTP.getResponseHeader("Location"))
   EndIf
   Status = oHTTP.Status
   StatusText = oHTTP.StatusText
   headers = oHTTP.GetAllResponseHeaders()
   Pause(oHTTP.Status, headers)
EndIf

;----------------------------------------------------------------------------
; Get Response
;----------------------------------------------------------------------------
JSON_Data = oHTTP.ResponseText
exit
;----------------------------------------------------------------------------
:UDFs
#DefineFunction B64GetCookie()
   B64Cookie=ArrDimension(256,2)  ; ,0 is to B64  ,1 if from B64
   ArrInitialize(B64Cookie,-1)
   AUPPER=Char2Num("A")
   alower=Char2Num("a")
   ZEROChr=Char2Num("0")

   For xx=0 To 25
      B64Cookie[xx,0]=Num2Char(AUPPER+xx)
      B64Cookie[xx+26,0]=Num2Char(alower+xx)
   Next

   For xx=52 To 61
      B64Cookie[xx,0]=Num2Char(ZEROChr+xx-52)
   Next

   B64Cookie[62,0]="+"
   B64Cookie[63,0]="/"

   For xx=0 To 63
       val=Char2Num(B64Cookie[xx,0])
       B64Cookie[val,1]=xx
   Next
   b64Cookie[Char2Num("="),1]=9999  ; flag the = sign

   Return(B64Cookie)
#EndFunction

#DefineFunction Base64StringFromClearString(B64Cookie,clearstring)
  s=StrLen(clearstring)
  bb=BinaryAlloc(s)
  BinaryPokeStr(bb,0,clearstring)
  b64bb=Base64BBFromClearBB(B64Cookie,bb)
  s=BinaryPeekStr(b64bb,0,BinaryEodGet(b64bb))
  BinaryFree(bb)
  BinaryFree(b64bb)
  Return(s)
#EndFunction

#DefineFunction Base64BBFromClearBB(B64Cookie,clearbb)
   ;clearbb contains bytes to be converted into base64 format
   ;how many triplets
   clearbytes=BinaryEodGet(clearbb)
   cleartriplets= clearbytes/3
   clearremnants= clearbytes mod 3
   ;if clearremnants !=0 then cleartriplets=cleartriplets+1
   b64quads=ClearTriplets
   If clearremnants!=0 Then b64quads=b64quads+1
   b64bytes= b64quads*4  + (b64quads/16)*2  + 6; 4bytes per quad + CRLF every 16 quads plus 6 in case I got the math wrong
   ;Only 16 quads per line allowed
   quadlinecount=0
   B64BB=BinaryAlloc(b64bytes)
   For xx= 1 To cleartriplets
      c1 = BinaryPeek(clearbb,(xx-1)*3+0)
      c2 = BinaryPeek(clearbb,(xx-1)*3+1)
      c3 = BinaryPeek(clearbb,(xx-1)*3+2)

      d1 =                      c1 >> 2
      d2 = ( (c1 &  3) << 4) | (c2 >> 4)
      d3 = ( (c2 & 15) << 2) | (c3 >> 6)
      d4 = ( (c3 & 63)     )
      quad=StrCat(B64Cookie[d1,0],B64Cookie[d2,0],B64Cookie[d3,0],B64Cookie[d4,0])
      BinaryPokeStr(b64BB,BinaryEodGet(b64bb),quad)
      quadlinecount=quadlinecount+1
      If (quadlinecount mod 16)==0 Then BinaryPokeStr(b64BB,BinaryEodGet(b64bb),@CRLF)
   Next xx
   Switch clearremnants
      Case 1
          c1=BinaryPeek(clearbb,(cleartriplets)*3+0)
          d1 =                      c1 >> 2
          d2 = ( (c1 &  3) << 4)
          quad=StrCat(B64Cookie[d1,0],B64Cookie[d2,0],"==")
          Continue
      Case 2
          c1=BinaryPeek(clearbb,(cleartriplets)*3+0)
          c2 = BinaryPeek(clearbb,(cleartriplets)*3+1)
          d1 =                      c1 >> 2
          d2 = ( (c1 &  3) << 4) | (c2 >> 4)
          d3 = ( (c2 & 15) << 2)
          quad=StrCat(B64Cookie[d1,0],B64Cookie[d2,0],B64Cookie[d3,0],"=")
          Continue
      Case 1
      Case 2
         BinaryPokeStr(b64BB,BinaryEodGet(b64bb),quad)
         quadlinecount=quadlinecount+1
         If (quadlinecount mod 16)==0 Then BinaryPokeStr(b64BB,BinaryEodGet(b64bb),@CRLF)
   EndSwitch
   Return(b64BB)
#EndFunction

Return
Title: Re: Sending an API-Key
Post by: stanl on November 19, 2017, 07:16:21 AM
Having done several similar web queries with returned JSON, the code you posted looks like it should work, but you didn't post the error or return code that was invalid. I have never needed to use a base64 conversion: str_64=Base64StringFromClearString(B64GetCookie(),StrCat(":",apikey)) so I cannot be of any help there. Maybe if others and Tony pitch in things will become clearer. BTW: this is an SSL request and those get tricky./
Title: Re: Sending an API-Key
Post by: hdsouza on November 19, 2017, 05:11:15 PM
Hi Stanl,

For :
"StatusText" I get "Bad Request"
"JSON_Data"  I get "{"status":400,"error_code":"LARGE_PARAMETER","message":"Request parameter too large: credential-key","id":0}"

I dont know If I need base64 either. Is there a way around it. I am in the blind here.
Thanks
Hil
Title: Re: Sending an API-Key
Post by: JTaylor on November 19, 2017, 06:00:42 PM
Why are you converting the key to base64?   Did something indicate that should be done?   Have you tried it without the base64 encoding?

Jim
Title: Re: Sending an API-Key
Post by: td on November 20, 2017, 06:51:31 AM
Concur with Jim and Stan.  Have never encountered a case where it was required to base-64 encode a web services app key.   The JSON response indicates that the request parameter is to large which is what happens to a string when it is base-64 encoded, i.e., it becomes longer.
Title: Re: Sending an API-Key
Post by: stanl on November 20, 2017, 10:15:04 AM
No harm in just trying

Code (WINBATCH) Select

oHTTP.SetRequestHeader("Authorization",apikey)


can't find 'Basic' in any of the samples for access in their doscs.
[EDIT]
Found it in the tech database, it was specific to a particular URL.
Title: Re: Sending an API-Key
Post by: hdsouza on November 20, 2017, 05:45:43 PM
Stanl, Did you mean like this....
I get an error on the last line "1298: COM: Error code not recognized"

Code (winbatch) Select

Invest_ID = "5166xxxx"
cURL = 'https://api.lendingclub.com/api/investor/v1/accounts/%Invest_ID%/availablecash'
apikey = 'GVsZuDKATPRlsajFiBCxxxxx'

oHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
oHTTP.SetRequestHeader("Authorization",apikey)
exit
Title: Re: Sending an API-Key
Post by: td on November 20, 2017, 09:57:07 PM
The exact requirements vary from vendor to vendor but here are a few lines from a working script used in a production environment.

Code (winbatch) Select
;; Error handling removed for readability.
objHttp=ObjectCreate("WinHttp.WinHttpRequest.5.1")
objHttp.SetTimeouts(50000, 50000, 50000, 50000);
objHttp.open("POST",strSquUrl,"False")
strAuth='Bearer ':strAccTok
objHttp.SetRequestHeader("Authorization", strAuth )
objHttp.SetRequestHeader("Accept", "application/json")
objHttp.SetRequestHeader("Content-Type", "application/json")
objHttp.Send(body)
if objHttp.Status != 200
   ;Blah blah blah error blah blah blah
endif
strResponse=objHttp.responseText


You would need to check your site's documentation carefully to determine what exactly it is expecting.
Title: Re: Sending an API-Key
Post by: stanl on November 21, 2017, 03:38:07 AM
Quote from: hdsouza on November 20, 2017, 05:45:43 PM
Stanl, Did you mean like this....
I get an error on the last line "1298: COM: Error code not recognized"

Code (winbatch) Select

Invest_ID = "5166xxxx"
cURL = 'https://api.lendingclub.com/api/investor/v1/accounts/%Invest_ID%/availablecash'
apikey = 'GVsZuDKATPRlsajFiBCxxxxx'

oHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
oHTTP.SetRequestHeader("Authorization",apikey)
exit


I meant just re-write the line in your original script. What you posted [above] should fail. Since you received a Json return in the original script we were just suggesting you remove the base64 stuff.
Title: Re: Sending an API-Key
Post by: hdsouza on November 21, 2017, 04:29:24 PM
Thanks TD.
I took your sample code and applied it to my script.
We may be a little closer. Now I get "StatusText" = "Unauthorized"
I believe strAuth has the incorrect format.
Verified that my api key is correct.
Any ideas?

Code (winbatch) Select

Invest_ID = "5166XXXX"
cURL = 'https://api.lendingclub.com/api/investor/v1/accounts/%Invest_ID%/availablecash'
apikey = 'GVsZuDKATPRlsaXXXXXXXXXXX'

oHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
oHttp.SetTimeouts(50000, 50000, 50000, 50000);
oHttp.open("POST",cURL,"False")
strAuth='Bearer ':apikey
oHttp.SetRequestHeader("Authorization", strAuth )   
oHttp.SetRequestHeader("Accept", "application/json")
oHttp.SetRequestHeader("Content-Type", "application/json")
oHttp.Send()
if oHttp.Status != 200
   If oHTTP.Status == 302
      Pause( "Server Attempted Redirect to: ", oHTTP.getResponseHeader("Location"))
   EndIf
   Status = oHTTP.Status
   StatusText = oHTTP.StatusText
   headers = oHTTP.GetAllResponseHeaders()
   Pause(oHTTP.Status, headers)
endif
strResponse=oHttp.responseText
exit


Also if it will help here is the Equivalent WORKING PHP code:
Code (php) Select

<?php
  $Invest_ID 
"5166XXXX";
  
$apikey 'GVsZuDKATPRlsaXXXXXXXXXXX';
  
define("DEBUG_LENDING_API"false);
  
$balance get_balance($Invest_ID$apikey);
  echo 
$balance;

  function 
get_balance($Invest_ID$apikey){
    
$balance_url "https://api.lendingclub.com/api/investor/v1/accounts/$Invest_ID/availablecash";
    
// to get balance call this
     
return call_curl($balance_url$apikey);
  }
  function 
call_curl($url$apikey$post "0"){
   
$ch curl_init();
   
curl_setopt($chCURLOPT_URL$url);
   
curl_setopt $chCURLOPT_USERAGENT"Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9) Gecko/2008052906 Firefox/3.0" );
   if(
$post != "0"){
     
curl_setopt($ch,CURLOPT_POST1);
     
curl_setopt($ch,CURLOPT_POSTFIELDS$post);
   }
   
curl_setopt $chCURLOPT_AUTOREFERERtrue );
   
curl_setopt $chCURLOPT_FOLLOWLOCATIONtrue );
   
$headers = array();
   
$headers[] = "Authorization: $apikey";
   
curl_setopt($chCURLOPT_HTTPHEADER$headers);
   
$server_output curl_exec ($ch);
   
$info curl_getinfo($ch);
   
curl_close ($ch);
   if(
DEBUG_LENDING_API == true){
     return array(
"data" => $server_output"response" => $info);
   }else{
     return 
json_decode($server_output);
   }
  }
?>

Title: Re: Sending an API-Key
Post by: stanl on November 22, 2017, 03:37:24 AM
Just looking at your last post.  There is no 'Bearer' in the PHP code and I don't believe the concatenation is necessary. Also, you probably should be using a GET not a POST (as was Tony's example - and the PHP code appears to use GET)
Title: Re: Sending an API-Key
Post by: hdsouza on November 22, 2017, 02:51:40 PM
You were right about the GET and not needing the concatenation.  That did the trick.
Thanks Stan and Tony !!!!
(This is just the first step and have several other things to do, so i may have a few more questions)