B4J Question Get request with post field

JanPRO

Well-Known Member
Licensed User
Longtime User
Hi,

currently I am trying to access a api for sending letters. The company provides a php class, however I want to use B4J.
Here is my problem:
In the php class one can see that the getPrice() funtion creates a Get request, but still has a post field:
B4X:
$opt_array[CURLOPT_CUSTOMREQUEST] = 'GET';
$opt_array[CURLOPT_POSTFIELDS] = $json;

Is it currently possible to implement this in B4J? Somehow I have to modify the request body, but it doesn't seem that there is a method/option for this.

Btw. this is how my current code looks like (I use a Post requets here as it makes the most sense for me, but the server returns a error, saying that the rescource (I guess the json string is meant) were not found)

B4X:
Sub GetPrice
    Dim Request As Map
    Request.Initialize
    Request.Put("auth",CreateMap("apikey":"KEY","username":"NAME"))
    Request.Put("letter",CreateMap("specification":CreateMap("page":"1","color":"1","mode":"simplex","ship":"national")))
   
    Dim J As JSONGenerator
    J.Initialize(Request)
   
    Dim H As HttpJob
    H.Initialize("GetPrice",Me)
    H.PostString("https://sandbox.letterxpress.de/v1/getPrice",J.ToString)
    H.GetRequest.SetContentType("application/json")
    H.GetRequest.SetHeader("User-Agent","MozillaXYZ/1.0")
   
    Wait For (H) JobDone(H As HttpJob)
   
    Log(H.GetString)
End Sub

Any ideas?

Jan
 
Last edited:

MarkusR

Well-Known Member
Licensed User
Longtime User
can not test it with apikey":"KEY","username":"NAME" or its really valid for this web api?
the manual is strange, a get request is typically a single url row with parameters.
 
Upvote 0

JanPRO

Well-Known Member
Licensed User
Longtime User
The correct key & username is not needed here to solve the problem, as the api currently can't even access the json string the way I send the request. When you get the following response

{"status":401,"message":"Anmeldung fehlgeschlagen"} (means, that the key or username is wrong)

the problem is solved, because this indicates that the service was able to read the json string.

the manual is strange, a get request is typically a single url row with parameters.
Indeed this is a quite unusual kind of request. The benefits of a get request with a message body are highly discussed in the internet ...

Jan
 
Last edited:
Upvote 0

MarkusR

Well-Known Member
Licensed User
Longtime User
i try to use a tcp socket and exchange POST with GET
but then it said
{"status":400,"message":"JSON Format nicht eingehalten"}

the http header ends with 2 line breaks then comes the payload with length same as set in content-length.

B4X:
Sub Process_Globals

    Dim soo As Socket

End Sub

B4X:
Sub AppStart (Form1 As Form, Args() As String)



    MainForm = Form1

    MainForm.Show
 
    Test

B4X:
Sub Test
 
    soo.InitializeSSL("Socket1",Null,"")
    soo.Connect("sandbox.letterxpress.de",443,1000)
    
End Sub

Sub Socket1_Connected(Successful As Boolean)

    Log(Successful)

    Dim Request As Map
    Request.Initialize
    Request.Put("auth",CreateMap("apikey":"KEY","username":"NAME"))
    Request.Put("letter",CreateMap("specification":CreateMap("page":"1","color":"1","mode":"simplex","ship":"national")))
 
    Dim J As JSONGenerator
    J.Initialize(Request)
 
    Dim json As String
    json = J.ToPrettyString(4)
 
    Dim send As String
    send = "GET /v1/getPrice HTTP/1.1" & Chr(13) & Chr(10)
    send = send & "Host: sandbox.letterxpress.de" & Chr(13) & Chr(10)
    send = send & "Content-Length: " & json.Length & Chr(13) & Chr(10)
    send = send & "Connection: keep-alive" & Chr(13) & Chr(10)
    send = send & "Content-Type: application/json" & Chr(13) & Chr(10)
    send = send & "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)" & Chr(13) & Chr(10)
    send = send & Chr(13) & Chr(10)
    send = send & Chr(13) & Chr(10)
    send = send & json
 
    Log(send)
 
    Dim out As OutputStream = soo.OutputStream
    Dim buffer() As Byte
    buffer = send.GetBytes("UTF8")
    out.WriteBytes(buffer,0,buffer.Length)
    out.Flush
    'out.Close

    Dim inp As InputStream = soo.InputStream
    Dim buffer(1024) As Byte
 
    If inp.IsInitialized=True Then Log("Jo")
 
    Dim count As Int
    Dim rec As String =""
 
    Dim exitcondition As Boolean
    exitcondition=False
 
    Do Until exitcondition
        'Header + Content-Length
        Log("Wait")
        Log("Connected " & soo.Connected)
        Sleep(1000)
    
        Log("BytesAvailable " & inp.BytesAvailable)
    
        'If inp.BytesAvailable > 0 Then
            Log("input")       
            count = inp.ReadBytes(buffer, 0, buffer.length)
            If count>0 Then
             rec = BytesToString(buffer,0,count,"UTF-8")
             Log(rec)
            End If
        'End If
    Loop
 
    Log("End")
End Sub
 
Last edited:
Upvote 0

JanPRO

Well-Known Member
Licensed User
Longtime User
Hi,

thank you very much. I guess that's the way to go now.
Your code works fine there was just a little mistake: Instead of 2 line breaks there are 3, which make the message body with the json string invalid.

Jan
 
Upvote 0

MarkusR

Well-Known Member
Licensed User
Longtime User
Instead of 2 line breaks there are 3
ups :)

i believe the source of http job also exists, maybe u can replace the POST with GET there for this request.
or maybe its possible to set the whole header itself there.
httpjob is better than raw socket.
 
Upvote 0

JanPRO

Well-Known Member
Licensed User
Longtime User
maybe u can replace the POST with GET there for this request.
Unfortunately, it doesn't seem to be possible.

Now, I am using your code with a AsynStream object:

B4X:
Sub GetWithBody(Host As String, HostPath As String, Post As String, TimeoutMS As Int) As ResumableSub
    Dim S As Socket
    S.InitializeSSL("S",Null,"")
    
    Dim RequestBody As String
    Dim NewLine As String = Chr(13) & Chr(10)
    RequestBody = $"GET ${HostPath} HTTP/1.1${NewLine}"$
    RequestBody = $"${RequestBody}Host: ${Host}${NewLine}"$
    RequestBody = $"${RequestBody}Content-Length: ${Post.Length}${NewLine}"$
    RequestBody = $"${RequestBody}Connection: keep-alive${NewLine}"$
    RequestBody = $"${RequestBody}Content-Type: application/json${NewLine}${NewLine}"$
    RequestBody = $"${RequestBody}${Post}"$
    
    S.Connect(Host,443,TimeoutMS)
    
    Wait For S_Connected (Successful As Boolean)
    
    If Successful Then
        Dim AsynS As AsyncStreams
        AsynS.Initialize(S.InputStream,S.OutputStream,"AsynS")
        AsynS.Write(RequestBody.GetBytes("UTF8"))
    Else
        Return "-1"
    End If
    
    Wait For AsynS_NewData (Buffer() As Byte)
    AsynS.Close
    Dim ResponseBody As String = BytesToString(Buffer,0,Buffer.Length,"UTF-8")
    Dim ResponseLines As List = Regex.Split(NewLine,ResponseBody)
    
    Dim Response As String = ResponseLines.Get(ResponseLines.Size -1)
    
    Return Response
End Sub

Jan
 
Upvote 0
Top