Examples of RESTful calls?

Started by kdmoyers, July 08, 2025, 04:51:13 AM

Previous topic - Next topic

kdmoyers

I was sure I'd find some examples of consuming a REST api in the tech database, but I'm coming up empty. What should I be searching for?
The mind is everything; What you think, you become.

spl

Restful calls usually return json.  I know I have posted several examples. Whether or not they got to Tech DB would be up to Tony. But for fun try below and check return
cUrl = "https://query1.finance.yahoo.com/v7/finance/quote?symbols=IBM,GOOG,AAPL"
request = Createobject("WinHttp.WinHttpRequest.5.1")
request.Open("GET", cUrl, @False )
request.Send()
json = request.ResponseText
ObjectClose(request)

Stan - formerly stanl [ex-Pundit]

td

I am not sure how to answer that one. There are several examples, but they tend to be associated with specific tasks. I know Stan has posted examples over the years. Many REST API providers have examples in Curl. Curl translations to WIL are generally straightforward.

REST API usage typically involves a combination of POST and GET HTTP verbs, utilizing JSON as the data format. HTTP headers are almost always required as well. 

I imagine you already know HTTP and HTML basics, but this longish tutorial is a good way to brush up.

https://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+Tutorials+HTTP~and~WinInet~-~An~Opus.txt

Here is a dummy example that may be of some use:
objHttp=ObjectCreate("Msxml2.XMLHTTP.6.0") ;WinHttp.WinHttpRequest.5.1") ; MSFT keeps Msxml2 in better shape. 

URL = "https://your.api.url.here/maybe some more required here" 
objHttp.open("POST",URL,"False") 
objHttp.SetRequestHeader("Authorization", "Bobs-Auth-Key some long 64bit number or something here" )    ; Put your key here!
objHttp.SetRequestHeader("User-Agent", "MyApp/1.1.1") ; Put your "app" name here!
objHttp.SetRequestHeader("Content-Length", "71")   ; Set the data length in bytes here
objHttp.SetRequestHeader("Accept", "application/json")
objHttp.SetRequestHeader("Content-Type", "application/json")    
Body = `{"whatever":["some json key":some json value}`
objHttp.Send(body)
while objHttp.readyState != 4 
   objHttp.WaitForResponse(10)
endwhile
Terminate(objHttp.Status != 200,"REST API", "You didn't do it correctly or the server is down")

strJson=objHttp.responseText
; You can use the JSON extender to extract the returned results.

This forum likely has a few better examples, if you can find them.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

and for more fun, here is an older script (probably pre-dates Json Extender, when ScriptControl object could be used to parse Json). Uses CLR instead of COM.
;Based on Tony's code to obtain Yahoo finance for multiple stocks; returns Json
IntControl(73,1,0,0,0)
Gosub udfs
symbols =  "IBM,GOOG,AAPL"
strUrl = "https://query1.finance.yahoo.com/v7/finance/quote?symbols=%symbols%"
ObjectClrOption('useany', 'System')
objWebUtil = ObjectClrNew('System.Net.WebUtility')

objUri = ObjectClrNew('System.Uri', strUrl)
objSvcManager = ObjectClrNew('System.Net.ServicePointManager')
protocols = ObjectClrType("System.Net.SecurityProtocolType",3072|768)  
objSvcManager.SecurityProtocol = protocols
objSvcPoint = objSvcManager.FindServicePoint(objUri)

objWebRequest = ObjectClrNew('System.Net.WebRequest')
objWebRequest = objWebRequest.Create(objUri)
objWebRequest.Timeout = objWebRequest.Timeout * 5
objResponse = objWebRequest.GetResponse()
objResponseStream = objResponse.GetResponseStream
Encoding = ObjectClrNew( 'System.Text.Encoding' )
objStreamReader = ObjectClrNew("System.IO.StreamReader", objResponseStream, Encoding.UTF8)

;convert json to comma-delimited file

strOut = 'c:\temp\Output.Json'
if FileExist(strOut) then FileDelete(strOut)
jdata = StrReplace(objStreamReader.ReadToEnd(),",",",":@LF)

Message("",Jlen(jdata))

output = GetJSON1(jdata)
hdr = "Key":@TAB:"Subkey":@TAB:"Value":@LF
output = hdr:StrReplace(output,",",@TAB)  ;change to Tab-delimited
FilePut(strOut, StrReplace (output, @LF, @CRLF))
if FileExist(strOut) then Display(2,'Json Data', strOut)
if FileExist(strOut) then Run('notepad.exe', strOut)
Exit


;=========================================================================================
:WBERRORHANDLER
Terminate(@TRUE,"Error Encountered",err())

:udfs
#DefineFunction err()
wberroradditionalinfo = wberrorarray[6]
lasterr = wberrorarray[0]
handlerline = wberrorarray[1]
textstring = wberrorarray[5]
linenumber = wberrorarray[8]
errmsg = "Error: ":lasterr:@LF:textstring:@LF:"Line (":linenumber:")":@LF:wberroradditionalinfo
Return(errmsg)
#EndFunction


#DefineFunction GetJSON(jdata)
If jdata == "" Then Return ""
objJSC = CreateObject ("MSScriptControl.ScriptControl")
objJSC.Language = "JScript"
;objJSC.AddCode(: `function json2txt(obj,path){var txt='';for(var key in obj){if(obj.hasOwnProperty(key)){if('object'==typeof(obj[key])){txt+=json2txt(obj[key],path+(path?'|':'')+key);}else{txt+=path+'|'+key+','+obj[key]+'\n';}}}return txt;}`)
code = $"
function json2txt(obj)
{
  var txt = '';
  var recurse = function(_obj) {
    if ('object' != typeof(_obj)) {
      txt += ',' + _obj + '\n';
    }
    else {
      for (var key in _obj) {
        if (_obj.hasOwnProperty(key)) {
          txt += key;
          recurse(_obj[key]);
        } 
      }
    }
  };
  recurse(obj);
  return txt;
}
$"
objJSC.AddCode(:code)
Return objJSC.Eval(: `json2txt(` : jdata : `,'')`)
; JS code from Patrick Fisher at "http://stackoverflow.com/questions/10221229/list-all-keys-and-values-of-json" ; 2012-04-19T03:48:24.
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction Keys(jdata)
If jdata == "" Then Return ""
objJSC = CreateObject ("MSScriptControl.ScriptControl")
objJSC.Language = "JScript"
objJSC.AddCode(: `function getKeys(obj,path){ var keys = new Array(); for (var i in obj) { keys.push(i); } return keys; }`)
Return objJSC.Eval(: `getKeys(` : jdata : `,'')`)
#EndFunction

#DefineFunction JSONDecode(jdata)
   objJSC = CreateObject ("MSScriptControl.ScriptControl")
   objJSC.Language = "JScript"
   data = objJSC.Eval(: `(` : jdata : `)` )
   Return(data)
#EndFunction


#DefineFunction Jlen(jdata)
   objJSC = CreateObject ("MSScriptControl.ScriptControl")
   objJSC.Language = "JScript"
   code = $"
   function Keylen(jsonObj) { 
   var keys = ''; 
   for (var n in jsonObj) { 
   keys += n + '|' ; } 
   return keys; 
   }
   $"
   objJSC.AddCode(:code)
   Return objJSC.Eval(: `Keylen(` : jdata : `,'')`)
#EndFunction

#DefineFunction UnixDate(d,ms)
   If ms Then d="00":d
   Ymd = TimeAdd('1970:01:01:00:00:00', d)
   Ymd = TimeFormat(Ymd,"MM/dd/yyyy")
   Return(Ymd)
#EndFunction

#DefineFunction GetJSON1(jdata)
If jdata == "" Then Return ""
objJSC = CreateObject ("MSScriptControl.ScriptControl")
objJSC.Language = "JScript"
code = $"
function json2txt(obj,path){
   var txt='';
   for(var key in obj){
      if(obj.hasOwnProperty(key)){
         if('object'==typeof(obj[key])){
         txt += json2txt(obj[key],path+(path?''::'')+key);}
         else{txt+=path+','+key+','+obj[key]+'\n';}
      }
   }
   return txt;
}
$"
objJSC.AddCode(:code)
Return objJSC.Eval(: `json2txt(` : jdata : `,'')`)
; JS code from Patrick Fisher at "http://stackoverflow.com/questions/10221229/list-all-keys-and-values-of-json" ; 2012-04-19T03:48:24.
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------
Return
Stan - formerly stanl [ex-Pundit]

spl

As PS has Invoke-RestMethod as a cmdlet, here is the simplest STD_Out script I could put together in 2-3 minutes to illustrate.

OT: but if you think about it, I have posted multiple Std_out scripts all with the same scenario
  • WB upfront code to create variables/input or output file
  • Simple argument variable with replace calls if needed
  • Single UDF for results

Now if the single UDF could be called from a data source holding fields for Description of Process; the argument; the list of replace; and the outcome... easy to create a dropdown list for conversions involving
db sources
csv
excel
json
xml
yaml

into a single script. {I've thought about it}
;Rest Query for IP Address
;Stan Littlefield 7/8/2025
;==========================================================
Gosub udfs

args = $"
$IPAddress = (curl -uri "http:://ifconfig.me/ip").Content
$LocationInfo = Invoke-RestMethod -Method Get -Uri "http:://ip-api.com/json/$IPAddress"
$LocationInfo 
$"
cmd="Powershell"
msg='IP Address

BoxOpen("Running...",cmd:" ":args:@LF:"PLEASE WAIT...MAY TAKE SOME TIME")
TimeDelay(2)
vals = Get_stdout():@LF:"Script Completed"
Message(msg,vals)  

;If FileExist(xml) Then Run("notepad.exe",xml)
Exit
;==========================================================
:udfs
#DefineSubroutine Get_stdout()
ObjectClrOption("useany","System")
objInfo = ObjectClrNew("System.Diagnostics.ProcessStartInfo")
Output=""
timeOut = ObjectType("I2",5000)
objInfo.FileName = cmd
objInfo.RedirectStandardError = ObjectType("BOOL",@TRUE)
objInfo.RedirectStandardOutput = ObjectType("BOOL",@TRUE)
objInfo.UseShellExecute = ObjectType("BOOL",@FALSE)
objInfo.CreateNoWindow = ObjectType("BOOL",@TRUE)
objInfo.Arguments = args
oProcess = ObjectClrNew("System.Diagnostics.Process")
oProcess.StartInfo = objInfo
BoxShut()
oProcess.Start()
oProcess.WaitForExit(timeout)
STDOUT = oProcess.StandardOutput.ReadToEnd()
STDERR = oProcess.StandardError.ReadToEnd()
Output = Output:STDOUT:@CRLF
If STDERR<>""
   Output = Output:"STDERR:":STDERR:@CRLF
Endif
oProcess = 0
objInfo = 0

Return (Output)
#EndSubroutine
Return
;==========================================================
Stan - formerly stanl [ex-Pundit]

spl

Finally, here is a real fun one... try this in your browser, then write WB code to translate the json

https://api.funtranslations.com/translate/morse.json?text=hello
Stan - formerly stanl [ex-Pundit]

td

I must be missing something again. It seems trivial to extract the values.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

For Example,
AddExtender('ilcjs44i.dll', 0, 'ilcjs64i.dll')
Mesage = 'Faliure to launch'
Data = $"{
    "success":: {
        "total":: 1
    },
    "contents":: {
        "translated":: ".... . .-.. .-.. --- ",
        "text":: "hello",
        "translation":: "morse"
    }
}$"

if jsValid(Data)

   h = jsParse(Data)
   nTotal = jsValueGet(h,'success.total')
   if ntotal 

      hCon = jsValueGet(h,'contents')
      Text = jsValueGet(hCon,'text')  
      Lang = jsValueGet(hCon,'translation') 
      Translation = jsValueGet(hCon,'translated') 
      Mes = 'Morris code for "':text:'" is "':Translation:'"'
   endif
   Pause('Translation', Mes)   
endif

jsConClose()
exit
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Quote from: td on July 08, 2025, 02:40:54 PMI must be missing something again. It seems trivial to extract the values.

It is with the Extender [shout out]. I was thinking more of getting the json with a Rest request, then parsing w/out prior knowledge of the node names. But I think Kirby has enough to work with.
cUrl = "https://api.funtranslations.com/translate/morse.json?text=hello"
request = Createobject("WinHttp.WinHttpRequest.5.1")
request.Open("GET", cUrl, @False )
request.Send()
json = request.ResponseText
ObjectClose(request)
Message("Response",json)

;then add you json Extender parsing
Stan - formerly stanl [ex-Pundit]

kdmoyers

So much goodness!!! thanks guys!!
-K
The mind is everything; What you think, you become.

spl

Quote from: kdmoyers on July 09, 2025, 09:14:04 AMSo much goodness!!! thanks guys!!
-K

You are most welcome. Below is a free/useful source to practice with, and an excellent workout for the Json Extender.
https://mixedanalytics.com/blog/list-actually-free-open-no-auth-needed-apis/
Stan - formerly stanl [ex-Pundit]

SMF spam blocked by CleanTalk