B4J Library Synchronous HTTP Request Library

IMPORTANT NOTE
There are many reasons you shouldnt use this library e.g. it will hold up your main thread. This is especially important for UI applications.

*** Please dont turn this thread into a sermon regarding synchronous vs asynchronous calls. It is for specific use cases ***


This is a wrapper for this library; https://github.com/kevinsawicki/http-request

An important distinction here is that this library does synchronous http requests. It will block your thread. It will affect UI. Basically you shouldnt use this unless you know why you need this library.

However if you have a console application, background process or some kind of application that needs to make many http calls in a specific order then this library will simplify your workflow.

Code Examples;

Generic GET - Return Status Code

B4X:
Dim req As HttpRequestWrapper

req.Initialize(URL,req.METHOD_GET)

req.trustAllCerts
req.trustAllHosts
req.followRedirects(True)

req.connectTimeout(1000)
req.readTimeout(1000)

Return req.code

Generic Get - Return Body

B4X:
Dim ParameterMap As Map ' These are your query strings
ParameterMap.Initialize
ParameterMap.Put(token,"ABCDEF")

Dim req As HttpRequestWrapper
      
req.Initialize(URL,req.METHOD_GET)
      
req.trustAllCerts
req.trustAllHosts
req.followRedirects(True)

If ParameterMap.Size > 0 Then req.form(ParameterMap)

Dim contentType As String = req.contentType

Dim body As String
body = req.body

Return body

Generic Post

B4X:
Dim ParameterMap As Map ' These are your query strings
ParameterMap.Initialize
ParameterMap.Put(token,"ABCDEF")

Dim req As HttpRequestWrapper

req.Initialize(URL,req.METHOD_POST)

req.trustAllCerts
req.trustAllHosts
req.followRedirects(True)

If ParameterMap.Size > 0 Then req.form(ParameterMap)

Dim contentType As String = req.contentType
Dim body As String = req.body

Return body
 

Attachments

  • HttpRequestWrapper.zip
    31 KB · Views: 37
Last edited:

peacemaker

Expert
Licensed User
Without any description of the class members it's rather hard to understand all well...
Now i have such code:

B4X:
'API request to the server to DELETE records
Public Sub API_DELETE(table As String, filter As Map)
    If others.Internet_Connected = False Then
        CallSubDelayed2(Me, "API_DELETE_DELETED", False)
        Return
    End If
    If table = "" Then
        CallSubDelayed2(Me, "API_DELETE_DELETED", False)
        Return
    End If
   
    If Main.BusySending Then Return
    Main.BusySending = True
   
    Log("API_DELETE: " & table)
   
    Dim m As Map
    m.Initialize
    m.Put("action", "delete")
    m.Put("scanner", others.Get_DeviceID)
    m.Put("key", API_KEY.ToLowerCase)
    Dim timestamp As Long = DateTime.Now / 1000
    m.Put("timestamp", timestamp)
    m.Put("dbtable", table)

    If filter <> Null Then
        If filter.IsInitialized Then
            If filter.Size > 0 Then
                m.Put("filter", filter)
            End If
        End If
    End If

    Dim jg As JSONGenerator
    jg.Initialize(m)
    Dim job As HttpJob
    job.Initialize("API_DELETE_" & table, Me)
    Dim text As String = jg.ToString
    #if debug
    Log(text)
    #End If
   
    job.PostString(URL, text)
    job.GetRequest.SetHeader("Content-Type", "application/json;charset=UTF-8")
    job.GetRequest.Timeout = 60000
   
    Wait For (job) JobDone(job As HttpJob)
    Dim jp As JSONParser
    If job.Success = False Then    'error
        Dim a As String = job.JobName & ": requesting error: " & job.ErrorMessage
        others.Add_ToLog(a, 3)
        Log(a)
        Main.BusySending = False    'allow next send
        job.Release
        others.Save_Blackbox_Logs
        CallSubDelayed2(Me, "API_DELETE_DELETED", False)
        Return
    End If
    #if debug
    Dim resString As String = job.GetString
    Log(resString)
    #End If
   
    'parsing
    Try
        jp.Initialize(job.GetString)
        Dim res As Map = jp.NextObject
        If res.IsInitialized = False Or (res.IsInitialized And res.Size = 0) Then
            API_Error(job)
            CallSubDelayed2(Me, "API_DELETE_DELETED", False)
            Return
        End If
    Catch
        API_Error(job)
        CallSubDelayed2(Me, "API_DELETE_DELETED", False)
        Return
    End Try
    Dim ret As String = res.Get("ret")
    Dim msg As String = res.Get("msg")
    If ret <> "ok" Then
        Dim msg As String = job.JobName & ": " & res.Get("msg")
        others.Add_ToLog(msg, 2)
        Log(a)
        Main.BusySending = False    'allow next send
        job.Release
        others.Save_Blackbox_Logs
        CallSubDelayed2(Me, "API_DELETE_DELETED", False)
        Return
    End If
   
    Main.BusySending = False    'allow next send
    job.Release    'OK parsed finally
    CallSubDelayed2(Me, "API_DELETE_DELETED", True)
End Sub

Sub API_Error(j As HttpJob)
Try
    Dim resString As String = j.GetString
    Dim a As String = j.JobName & ": server error reply: " & resString
    others.Add_ToLog(a, 3)
    Log(a)
    j.Release
Catch
    Log("API_Error.error: " & LastException.Message)
End Try

Main.BusySending = False    'allow next send
End Sub


'usage
 Sub Several_HTTP_requests
    If others.Internet_Connected = False Then Return
    Dim f As Map
    f.Initialize
    f.Put("scanner_name", others.Get_DeviceID)
    API_DELETE("loops", f)
    Wait for API_DELETE_DELETED (Success As Boolean)
    If Success = False Then
        Log("Send_loop deleted: " & Success)
        Return
    End If
'if deleted OK - next requests to CREATE records
....
End sub

Rather full control here. I'd like to preserve such control if to edit this API_DELETE sub to synchronous.

How to just make POST request of a plain text ?
 
Last edited:

peacemaker

Expert
Licensed User
Aha, i have found that
B4X:
req.send(text)    'to make the POST request
But if no Internet connection it throws the runtime exception com.github.kevinsawicki.http.HttpRequest$HttpRequestException: java.net.UnknownHostException: google.com.

@tchart, if you use this your lib yourself, possible to give some more wide code example how to use correctly in all the cases ? Errors trapping ?

edited, some tests, here catched 3 types of runtime fatal errors:
B4X:
req.Initialize("https://kyfw.12306.cn/", req.METHOD_POST)
    req.header("Content-Type", "application/json;charset=UTF-8")
    req.connectTimeout(250)   'testing CN slow web-site and small timeout
    req.trustAllCerts
    req.trustAllHosts
    req.followRedirects(True)
    Try
        req.send("test")    'make request
    Catch
        Log("Catch: " & req.code)    '0 = wrong host or no Internet or timeout error
        Return
    End Try
    Try
        If req.ok = False Then
            Log("Non-200 reply: " & req.code)
            Return
        End If
    Catch
        Log("req.ok.error: " & req.code)    '0 = at timeout error
    End Try
   
    Log(req.body)
 
Last edited:

peacemaker

Expert
Licensed User
In whole the lib can be used synchronously, thanks !
B4X:
Public Sub API_DELETE(table As String, filter As Map)
    If others.Internet_Connected = False Then
        Return
    End If
    
    If Main.BusySending Then
        Return
    End If
    Main.BusySending = True
    
    Log("API_DELETE: " & table)
    
    Dim m As Map
    m.Initialize
    m.Put("action", "delete")
    m.Put("scanner", others.Get_DeviceID)
    m.Put("key", API_KEY.ToLowerCase)
    Dim timestamp As Long = DateTime.Now / 1000
    m.Put("timestamp", timestamp)
    m.Put("dbtable", table)

    If filter <> Null Then
        If filter.IsInitialized Then
            If filter.Size > 0 Then
                m.Put("filter", filter)
            End If
        End If
    End If

    Dim jg As JSONGenerator
    jg.Initialize(m)
    Dim text As String = jg.ToString
    #if debug
    Log(text)
    #End If
    
    
    Dim req As HttpRequestWrapper

    req.Initialize(URL,req.METHOD_POST)
    req.header("Content-Type", "application/json;charset=UTF-8")
    req.connectTimeout(60000)
    req.trustAllCerts
    req.trustAllHosts
    req.followRedirects(True)
    Dim error_text_template As String = "Network error at " & "API_DELETE_" & table & " "
    Try
        req.send(text)    'make request
        If req.ok = False Then
            Dim a As String = "Server response: " & req.code & "; " & error_text_template & LastException.Message
            others.AddToLog(a)
            Log(a)
            Return
        End If
    Catch
        Log(error_text_template & LastException.Message)
        Return
    End Try
    Dim ResString As String = req.body
    Dim jp As JSONParser
    #if debug
    Log(ResString)
    #End If
    
    'parsing
    Try
        jp.Initialize(ResString)
        Dim Res As Map = jp.NextObject
        If Res.IsInitialized = False Or (Res.IsInitialized And Res.Size = 0) Then
            Log("Network error: " & LastException.Message, 3)
            Return
        End If
    Catch
        Log("JSON parsing error: " & LastException.Message)
        Return
    End Try
    Dim ret As String = Res.Get("ret")
    Dim msg As String = Res.Get("msg")
    If ret <> "ok" Then
        Dim msg As String = "API_DELETE_" & table & ": " & Res.Get("msg")
        others.Add_ToLog(msg, 2)
        Log(msg)
        Main.BusySending = False    'allow next send
        Return
    End If
    
    Main.BusySending = False    'allow next send
End Sub
 

EnriqueGonzalez

Well-Known Member
Licensed User
Hi!
today i wanted to implement the library but when i went to the Github project i saw that the last update was made 9 years ago, i also noticed that it is just a convenient wrapper for net classes that comes already in the JDK so i decided to wrap them.

The functionality is a bit different but may be someone is interested.
Right now you can do GET and POST.

The only issue is that i dont really now when the actual call happens. AFAIK it happens until you call one of the following method: getResponseAsText, getResponseAsBytes, getResponseCode.

example of GET:
B4X:
    Dim huc As HttpURLConnection
    huc.Initialize("https://postman-echo.com/get?foo1=bar1&foo2=bar2","GET")
    Log(huc.ResponseCode)
    Log(huc.getResponseAsText("UTF8"))

example of POST file:
B4X:
    Dim by() As Byte = File.ReadBytes("C:\temp","image.jpeg")
    Dim url As String = $"someurl"$
    Dim huc As HttpURLConnection
    huc.Initialize(url,"POST")
    huc.setRequestProperty("Content-Type","application/octet-stream")
    huc.setRequestProperty("Ocp-Apim-Subscription-Key",keyPoint)
    
    huc.postBytes(by)
    Log(huc.ResponseCode)
    Log(huc.getResponseAsText("UTF8"))
 

Attachments

  • HttpURLConnection.bas
    2.1 KB · Views: 14

tchart

Well-Known Member
Licensed User
Hi!
today i wanted to implement the library but when i went to the Github project i saw that the last update was made 9 years ago, i also noticed that it is just a convenient wrapper for net classes that comes already in the JDK so i decided to wrap them.

The functionality is a bit different but may be someone is interested.
Right now you can do GET and POST.

Correct the original library is very old. As you state it is just a wrapper for simplicity and convenience. Thanks for sharing your library.
 
Top