B4J Question I need a synchronous HTTP Post

ranul

Member
Licensed User
Longtime User
Hi,

Is there a way to do a synchronous HTTP POST request?
I don't want to use a resumable sub.
I just want to send a request and wait for it to return.

Thanks
 
Solution
But in the second code (see here below), I nested the function, and it doesn't work. Form is displayed without waiting. Why?!
Note the first line in the Resumable subs tutorial that @Erel linked to in post #10:
Remember that that a call to Sleep or Wait For in a resumable sub causes the code flow to return to the parent.
In your second example you are not waiting for SendRequest to complete in AppStart, so as soon as the code hits ' Wait For(PostRequest)...' it returns to the AppStart sub, loads the layout, and shows MainForm.

If you want to wait all the way through, you need to call all resumable subs in the chain with Wait For, right back to the point at which the first resumable sub is called (anything...

ranul

Member
Licensed User
Longtime User
Making requests on the main thread is the wrong solution. It would have caused your app to freeze anywhere between a few seconds to a minute+.

You can do whatever you need, including showing the main form after the request completed, with Wait For.
I am using Wait For.

I am sending the request, but while waiting for the response - the main form is shown.
 
Upvote 0

ranul

Member
Licensed User
Longtime User
Don't call MainForm.Show before the response arrived.
This is an example.
The response comes only after the MainForm is shown.


B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    PostRequest
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
End Sub
Private Sub PostRequest()
    Dim j As HttpJob
    
    j.Initialize("",Me)
    j.PostString("https://example.com", "example")
    Wait for (j) JobDone(j As HttpJob)
    If j.Success Then
        Log(j.GetString)
    End If
    j.Release
    
End Sub
 
Upvote 0

Num3

Active Member
Licensed User
Longtime User
My 2cents:

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    PostRequest
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
End Sub
Private Sub PostRequest()
    Dim j As HttpJob
    
    j.Initialize("",Me)
    j.PostString("https://example.com", "example")
    Wait for (j) JobDone(j As HttpJob)
    If j.Success Then
        Log(j.GetString)
        
            MainForm.Show '<------------
        
    End If
    j.Release
    
End Sub
 
Upvote 1

ranul

Member
Licensed User
Longtime User
This is it. Thank you.
So in the first code, seen here, it works as expected. The flow of the program is halted until function PostRequest is finished
But in the second code (see here below), I nested the function, and it doesn't work. Form is displayed without waiting. Why?!

Works good:

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    Wait For(PostRequest) Complete (Result As Int)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
End Sub
Private Sub PostRequest() As ResumableSub
    Dim j As HttpJob
    
    j.Initialize("",Me)
    j.PostString("https://example.com", "example")
    Wait for (j) JobDone(j As HttpJob)
    If j.Success Then
        Log(j.GetString)
    End If
    j.Release
    
    Return 0
    
End Sub


Works bad:

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    SendRequest
    
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
End Sub
Private Sub SendRequest()
    Wait For(PostRequest) Complete (Result As Int)
End Sub
Private Sub PostRequest() As ResumableSub
    Dim j As HttpJob
    
    j.Initialize("",Me)
    j.PostString("https://example.com", "example")
    Wait for (j) JobDone(j As HttpJob)
    If j.Success Then
        Log(j.GetString)
    End If
    j.Release
    
    Return 0
    
End Sub
 
Upvote 0

Chris2

Active Member
Licensed User
But in the second code (see here below), I nested the function, and it doesn't work. Form is displayed without waiting. Why?!
Note the first line in the Resumable subs tutorial that @Erel linked to in post #10:
Remember that that a call to Sleep or Wait For in a resumable sub causes the code flow to return to the parent.
In your second example you are not waiting for SendRequest to complete in AppStart, so as soon as the code hits ' Wait For(PostRequest)...' it returns to the AppStart sub, loads the layout, and shows MainForm.

If you want to wait all the way through, you need to call all resumable subs in the chain with Wait For, right back to the point at which the first resumable sub is called (anything with a call to Sleep or Wait For is a resumable sub).
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    Wait For(SendRequest) Complete (Result As Int)

    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
End Sub
Private Sub SendRequest() As ResumableSub
    Wait For(PostRequest) Complete (Result As Int)
    Return Result
End Sub
Private Sub PostRequest() As ResumableSub
    Dim j As HttpJob
   
    j.Initialize("",Me)
    j.PostString("https://example.com", "example")
    Wait for (j) JobDone(j As HttpJob)
    If j.Success Then
        Log(j.GetString)
    End If
    j.Release
   
    Return 0
   
End Sub
I don't think that you necessarily have to return a value from SendRequest, but I think it looks neater to do so if there's something that could be returned, even if you're not going to use it.
See the first tip in the tutorial:
- If you don't need to return a value but still want to wait for the resumable sub to complete then return Null from the resumable sub and set the type in the calling sub to Object
 
Upvote 0
Solution

Erel

B4X founder
Staff member
Licensed User
Longtime User
Chris2 answer above is accurate.
I understand why you created this SendRequest method but it doesn't do anything useful and only makes the code more complicated. It should be removed.
There is no way to "hide" the Wait For call. Once you understand how resumable subs work it will become clear. The Wait For / Sleep calls are what causes your sub to become a resumable sub and allow the code to wait for some event.

A direct call will never block.
 
Upvote 0
Top