This is my first technical article on this blog. To reach a broader audience in the Notes/Domino community (and to avoid weird translations), I decided to write technical articles in English. Other experiences and opinions on the Notes/Domino world will stay in Dutch.
That being said, I wanted to discuss the new functions in LotusScript to do HTTP Requests and parsing the json response to use it in a Notes application.
You can use the new NotesHTTPRequest class to do the api request. This class allows you to do get, put and post requests. You can set headers using the setHeaderField method.
By default, the returned response can be either a byte array or a string (depending on the service called). To avoid this, set the (undocumented) preferString property to true. This will enforce the response to be a string.
Dim webRequest As NotesHTTPRequest
Set webRequest = session.createhttprequest()
'Get the response
Dim response As String
webrequest.preferstrings = True
response = webrequest.Get(<URL>)
'Throw error if response status is not OK
If InStr(webRequest.Responsecode, "200 OK") = 0 Then
'Return Status is not OK
Error 1000, "Request returned response code " + webRequest.responseCode
End If
Note that the URL that you pass to the request has to be encoded. Most browsers encode the url after you typed it in the addressbar. But the NotesHTTPRequest does not. Therefor, make sure you encode the url before using it for the request. Here’s a small example:
Dim url as string
url = "https://mysite.com/get?name=John Doe"
'Using this url in the get request won't work
response = webrequest.get(baseurl + parameters)
'By encoding the url, it will
response = webrequest.get(urlEncode(url))
%REM
I use this function to encode url parts
It will encode special characters, but won't touch & or =,
so you can pass the full url in one go
Kuddos to
http://dominonotes.blogspot.com/2008/11/lotusscript-equivalents-for-urlencode.html
%END REM
Function urlEncode(s As String) As String
If Len(s) = 0 Then Exit Function
Dim tmp As String
Dim c As String
Dim i As Integer
For i = 1 To Len(s)
c = Mid(s, i, 1)
If (Asc(c) >= 65 And Asc(c) <= 90) _
Or (Asc(c) >= 97 And Asc(c) <= 122) _
Or (Asc(c) >= 48 And Asc(c) <= 58) _
Or Asc(c) = 38 _
Or (Asc(c) >= 45 And Asc(c) <= 47) _
Or Asc(c) = 58 Or Asc(c) = 61 _
Or Asc(c) = 63 Or Asc(c) = 126 Then
tmp = tmp + c
Else
tmp = tmp + "%" + Hex(Asc(c))
End If
Next i
urlEncode = tmp
End Function
You can now parse the response using the NotesJSONNavigator class. However, this still has some caveats. The new class doesn’t behave well on some special characters in the json you pass (like CR, LF, °, ü, …) and you’ll get an error trying to parse this. According to HCL, there might still be an issue with the character encoding while processing the json data.
However, there is a workaround to avoid this by forcing the data to UTF-8. When you save the response to a file and then read it using a notesstream with UTF-8 encoding, you will be able to parse the data (Thanks to Dave Cohen for the tip)
'write the requests response to a file
Dim fileNum As Integer
fileNum% = FreeFile()
Dim filepath As String
filepath = "c:\temp\" + Format(Now, "yyyy-mm-dd-hhnnss") + ".json"
Open filepath For Output As fileNum%
Print #filenum, response
Close filenum
'Read the file using a NotesStream
Dim inbuf As NotesStream
Dim json As variant
Set inbuf = session.Createstream()
If Not(inbuf.Open(filepath, "UTF-8")) Then
Error 1001, "Unable to open JSON file (" + filepath + ")"
End If
json = inbuf.Read()
Call inbuf.Close()
'remove temporary file
Kill filepath
'Create the Json Navigator to parse the data
Dim jsnav As NotesJSONNavigator
If IsArray(json) Then
Set jsnav = session.CreateJSONNavigator(json)
Else
Error 1002, "JSON is nothing"
End If
Once you have the NotesJSONNavigator object, you can loop through the different elements. Here’s some sample code to do so.
Dim parsed As string
Dim el As notesjsonelement
Set el = jsnav.Getfirstelement()
While Not el Is Nothing
parsed = parsed + parseelement(el, "")
Set el = jsnav.Getnextelement()
Wend
MsgBox parsed
Function parseElement(el As notesjsonelement, parent As string)
Dim returnValue As String
Dim sName As String
sName = parent + el.name
Select Case el.type
Case 1: 'Object
Dim ob As notesjsonobject
Set ob = el.value
returnValue = returnValue + parseObject(ob, parent + el.name)
Case 2: 'Array
Dim ar As NOTESJSONARRAY
Set ar = el.value
returnValue = returnValue + parseArray(ar, parent + el.name)
Case 3: 'String
returnValue = returnValue + sName + " - '" & el.Value & "'" + Chr$(10)
Case 4: 'Number
returnValue = returnValue + sName + " - " & el.value + Chr$(10)
Case 5: 'Boolean
Dim b As String
If el.value Then
returnValue = returnValue + sName + " - true" + Chr$(10)
Else
returnValue = returnValue + sName + " - false" + Chr$(10)
End If
Case 64: 'empty
returnValue = returnValue + sName + " - <EMPTY>" + Chr$(10)
Case Else: 'Unknown
returnValue = returnValue + sName + " Unknown type " & el.type + Chr$(10)
End Select
parseElement = returnValue
End Function
Function parseObject(ob As notesjsonobject, parent As String) As string
Dim el As notesjsonelement
Dim sName As String
Dim returnValue As string
Set el = ob.Getfirstelement()
While Not el Is Nothing
returnValue = returnValue + parseElement(el, parent + ".")
Set el = ob.Getnextelement()
Wend
parseObject = returnValue
End Function
Function parseArray(ar As NOTESJSONARRAY, parent As String)
Dim el As notesjsonelement
Dim sName As String
Dim returnValue As String
Set el = ar.Getfirstelement()
Dim counter As Integer
While Not el Is Nothing
returnValue = returnValue + parseElement(el, parent + "." & counter)
Set el = ar.Getnextelement()
counter = counter + 1
Wend
parseArray = returnValue
End Function
Another way to get a json element is to get it by name or by pointer. A
JSON Pointer defines a string syntax for identifying a specific value within a JavaScript Object Notation (JSON) document.
'By name
Set el = jsnav.Getelementbyname("latitude")
'By pointer
Set el = jsnav.getElementbypointer("/daily/data/0")
I created a demo application that allows youto retrieve a weather forecast for any place on earth. I used the Google Maps API to retrieve address information and the Dark Sky API to get a forecast. You’ll need a key for both api to be able to use the app. You can download the demo here.