2

I'm trying to retrieve data from an API but my variable doesn't update even if I set it as nothing before the GET request.

The data of the variable update only if I close Excel and re-open it.

Is there any explanation for it? I've been scratching my head for so long.

Here is the code

Sub getJsonResult()
    Dim objRequestt As Object
    Dim strUrl As String
    Dim blnAsync As Boolean
    Dim strUrlXBTUSD As String
    Dim strResponse As String
    Dim jsonText As String
    Dim jsonObject As Object, item As Object
    Dim i As Integer

    'setting up the variable to 0 or nothing

    strUrlXBTUSD = ""
    strResponsee = ""
    jsonText = ""
    i = 0
 blnAsync = False
 Set item = Nothing
 Set jsonObject = Nothing
 Set objRequestt = Nothing
 Set objRequestt = CreateObject("MSXML2.XMLHTTP")
    strUrlXBTUSD = "https://www.bitmex.com/api/v1/orderBook/L2?symbol=XBTUSD&depth=3"
    blnAsync = True


    'Starting the GET request

    ThisWorkbook.Activate
    With objRequestt
        .Open "GET", strUrlXBTUSD, blnAsync
        .SetRequestHeader "Content-Type", "application/json"
        .send
        strResponse = .responseText 'here the response is always the same except if i Close Excel
           Debug.Print strResponsee
    End With
End Sub

At the end "strResponse" is always the same even after several F5 refresh. I can see that the data are no longer accurate on a web browser. I'd like the VBA program to get accurate data and refresh without closing Excel.

How to do that?

Pᴇʜ
  • 56,719
  • 10
  • 49
  • 73
polo31
  • 47
  • 1
  • 10
  • Is the GET request being cached, by chance? – user2864740 Mar 16 '19 at 19:54
  • 1
    Also, should probably force sync mode..? There is no attached callback handler so I’m surprised that there is even a first ‘successful’ fetch. – user2864740 Mar 16 '19 at 19:56
  • You are calling it asynch. *varAsync [optional] Boolean. Indicator of whether the call is asynchronous. The default is True (the call returns immediately). If set to True, attach an onreadystatechange property callback so that you can tell when the send call has completed.*. Most of your lines of code are completely unnecessary and slow your code down. Variables default to `nothing`/`false`/`0`/`""` – Noodles Mar 16 '19 at 19:57
  • hello @user2864740, i'm not sure if it's cached. How to check it ? What should I do if so and if not ? – polo31 Mar 16 '19 at 19:57
  • Hello @Noodles! Can you explain more how to attached a onreadystatechange please ? I never used such a thing! – polo31 Mar 16 '19 at 20:00
  • You cannot program without Help open - for this object https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms759148(v%3Dvs.85) and for VBScript http://download.microsoft.com/download/winscript56/Install/5.6/W982KMeXP/EN-US/scrdoc56en.exe – Noodles Mar 16 '19 at 20:01
  • Examples are in Help. But you don't need to. Call synchronous. The rest of your code is expecting a synchronous object. – Noodles Mar 16 '19 at 20:02
  • @Noodles I don't think my problem is linked to my "blnAsync" variables. I can set it to FALSE, TRUE or even delete it i'd still have the same results. Can you explain more what you are thinking please ? – polo31 Mar 16 '19 at 20:07
  • You don't think that - great. Funny how experts like you need to ask questions. – Noodles Mar 16 '19 at 20:14
  • @Noodles no offense, thinking is not being sure! i'm trying to understand! – polo31 Mar 16 '19 at 20:18
  • Synchronous - the statement completes and returns the data. Asynchronous - the statement does not wait for the data but goes on to the next statement and you provide a callback function. As a vbscript exits after the last line - your program isn't around for the callback to happen. – Noodles Mar 16 '19 at 21:14

2 Answers2

2

You can add an instruction to avoid being served cached results (server can ignore this but I have had good success with this in the past). Make sure your async argument is always False and leave more time between tests. I notice that sometimes the prices are slow to change so you may miss the change due to too small an interval/not enough attempts. You will notice the size change though. You should add a max timeout to the loop in the bottom script.

Also removed the hungarian notation.

Option Explicit

Public Sub getJsonResult()
    Dim http As Object
    Dim urlXBTUSD As String
    Dim response As String
    Dim j As Long
    Const ASYNC_ARG As Boolean = False

    Set http  = CreateObject("MSXML2.XMLHTTP")
    For j = 1 To 10
        response = vbNullString
        urlXBTUSD = "https://www.bitmex.com/api/v1/orderBook/L2?symbol=XBTUSD&depth=3"

        With http 
            .Open "GET", urlXBTUSD,  ASYNC_ARG
            .setRequestHeader "Content-Type", "application/json"
            .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
            .send
            response = .responseText
            Debug.Print response
        End With
        Application.Wait Now + TimeSerial(0, 0, 15)
    Next
End Sub

Here is a long and tedious way of proving it by looping until price of first item in return collection changes. I use jsonconverter.bas added to project and VBE > Tools > References > Microsoft Scripting Runtime reference.

Option Explicit

Public Sub getJsonResult()
    Dim http  As Object
    Dim urlXBTUSD As String
    Dim response As String
    Dim j As Long
    Const ASYNC_ARG As Boolean = False
    Dim price As String, firstValue As String

    Set http  = CreateObject("MSXML2.XMLHTTP")
    urlXBTUSD = "https://www.bitmex.com/api/v1/orderBook/L2?symbol=XBTUSD&depth=3"

    With http 
        .Open "GET", urlXBTUSD,  ASYNC_ARG
        .setRequestHeader "Content-Type", "application/json"
        .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
        .send
         firstValue = JsonConverter.ParseJson(.responseText)(1)("price")
        Debug.Print  firstValue
        Do
            .Open "GET", urlXBTUSD, blnAsync
            .setRequestHeader "Content-Type", "application/json"
            .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
            .send
            price = JsonConverter.ParseJson(.responseText)(1)("price")
            Application.Wait Now + TimeSerial(0, 0, 5)
        Loop While price = firstValue
        Debug.Print price
    End With
End Sub
QHarr
  • 83,427
  • 12
  • 54
  • 101
  • 1
    The ."setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"" does change the result! If you remove it my problem comes back even with the asynch boolean set to FALSE or TRUE. I understand that I always have to set the asynch boolean as FALSE but it wasn't the problem. Thanks now it's working. – polo31 Mar 17 '19 at 18:54
0

This is for diagnostic purposes.

On Error Resume Next
Set File = WScript.CreateObject("Msxml2.XMLHTTP.6.0")
File.Open "GET", "https://www.google.com.au/search?q=cat", False
File.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 1.1.4322; .NET CLR 3.5.30729; .NET CLR 3.0.30618; .NET4.0C; .NET4.0E; BCD2000; BCD2000)"
File.Send

wscript.echo "==================" 
    wscript.echo "" 
    wscript.echo "Error " & err.number & "(0x" & hex(err.number) & ") " & err.description 
    wscript.echo "Source " & err.source 
    wscript.echo "" 
    wscript.echo "Server Response " & File.Status & " " & File.StatusText
    wscript.echo    File.getAllResponseHeaders
    wscript.echo    File.ResponseBody
Noodles
  • 194
  • 1
  • 4
  • Thank you very much Noodles for your contribution. My problem is now solved I had to add a .setRequestHeader specification as described in the previous post. – polo31 Mar 17 '19 at 18:59