B4J Question Entering Curl Command as HTTP in B4x

AKJammer

Active Member
Licensed User
Hey All,

I'm in the same boat as Colin Evans was in question https://www.b4x.com/android/forum/threads/how-to-enter-a-curl-command-as-an-https-request.116932/, but my curl is structured differently. Is there some tutorial where we can find the breakdowns of the different flags in a curl to be able to create the command in B4X? I'm trying to integrate the Vonage SMS messenger service (formerly Nexmo) into my B4J application for user notifications. The curl example they give is:

B4X:
curl -X "POST" "https://rest.nexmo.com/sms/json" \
     -d "from=15558889999" \
     -d "text=Hello from Vonage SMS API" \
     -d "to=15552279966" \
     -d "api_key=9******8" \
     -d "api_secret=N************g"

Any help would be appreciated.
Thanks,
Jim
 

Sandman

Expert
Licensed User
Longtime User
Your example looks like one of the easier ones to convert to B4X. You should be able to find lots of examples in the forum on how to post with data.

As for curl flags, take a look here: https://man.cx/Curl
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Create a json file with all the -d Values and do a poststring with okhttputils2

B4X:
dim m as map
m.initialize
'   -d "from=15558889999" \
m.put("from","15558889999")
'     -d "text=Hello from Vonage SMS API" \
m.put("text","ghello")
'     -d "to=15552279966" \
m.put("to","15552279966")
'     -d "api_key=9******8" \
m.put("api_key","xxxx")
'     -d "api_secret=N************g"
m.put("api_secret","xxxx")
dim json as JSONGenerator
json.initialize(m)
 
Upvote 0

AKJammer

Active Member
Licensed User
Thanks, the link was very helpful. It explained a lot. Still not sure about JSON and such. But am experimenting...
 
Upvote 0

AKJammer

Active Member
Licensed User
I found an example for clickatell that worked so was working with that. Switched over to the JSON generator, and I think I'm close. It says success, but not receiving any texts.

B4X:
Sub vonage (Phone As String, Message As String)

'    https://rest.nexmo.com/sms/json?from=15558889999&api_key=xxxxxx&api_secret=yyyyyyyyyy" \
'    -d "to=15552279966" \
'    -d "text=You are Registered in 3 contests with Bib 982"

    Dim m As Map
    m.Initialize
    m.Put("from", myFromNumber)
    m.Put("api_key", txtKey.text)
    m.Put("api_secret", txtSecret.text)
    m.Put("to", Phone)
    m.Put("text", Message)

    Dim json As JSONGenerator
    json.initialize(m)
    
    Dim stringtosend As String = json.ToString
    
    Log(stringtosend)

    Dim j As HttpJob
    j.Initialize("sms", Me)
    j.poststring("https://rest.nexmo.com/sms/json?",json.ToString )
    
    Wait For (j) JobDone(j As HttpJob)
    
    If j.Success=True Then
        Log("success")
        j.Release
    Else
        'do something'
        Log("ugh")
        j.Release
    End If

    
End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
It says success,
You probably should log what the service returned. Just because it returns a 200 response does not necessarily mean that the returned message does not contain information about an issue.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
-d, --data <data>

(HTTP MQTT) Sends the specified data in a POST request to the HTTP server, in the same way that a browser does when a user has filled in an HTML form and presses the submit button. This will cause curl to pass the data to the server using the content-type application/x-www-form-urlencoded. Compare to -F, --form.

So you are maybe (don´t know exactly) better with this one.
B4X:
 Dim m As Map
    m.Initialize
    m.Put("from", myFromNumber)
    m.Put("api_key", txtKey.text)
    m.Put("api_secret", txtSecret.text)
    m.Put("to", Phone)
    m.Put("text", Message)
job.PostMultipart(link,m,null)
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Looking at their coding samples (https://developer.nexmo.com/messaging/sms/overview), the API returns a JSON structure (in your case) that contains a status code field. If this field is not 0, then you have issues. The API does not use non-200 HTTP codes for these errors. So j.Success will be true, but j.GetString will contain the JSON structure that you'll have to decode to see if everything did go as expected.
 
Upvote 0

AKJammer

Active Member
Licensed User
ah, that was helpful. It says I'm missing the api_key.
B4X:
Waiting for debugger to connect...
Program started.
{"api_key":"8*****d","from":"15558889999","to":"15552279966","text":"You are Registered in 3 Contests with Bib 455\n    JJ WCS Novice (Lead)\n    Strictly Swing A (Lead) Partner: Mercer, Lori\n    JJ Hustle Novice (Lead)","api_secret":"N************g"}
{
    "message-count": "1",
    "messages": [{
        "status": "2",
        "error-text": "Missing api_key"
    }]
}
success

I tried adding the jsonmultipart as well

B4X:
Sub vonage (Phone As String, Message As String)

'    https://rest.nexmo.com/sms/json?from=15558889999&api_key=xxxxxx&api_secret=yyyyyyyyyy" \
'    -d "to=15552279966" \
'    -d "text=You are Registered in 3 contests with Bib 982"

    Dim m As Map
    m.Initialize
    m.Put("from", myFromNumber)
    m.Put("api_key", txtKey.text)
    m.Put("api_secret", txtSecret.text)
    m.Put("to", Phone)
    m.Put("text", Message)

    Dim json As JSONGenerator
    json.initialize(m)
    
    Dim stringtosend As String = json.ToString
    
    Log(stringtosend)

    Dim j As HttpJob
    j.Initialize("sms", Me)
'    j.poststring("https://rest.nexmo.com/sms/json",json.ToString )

    Dim link As String = "https://rest.nexmo.com/sms/json"
    j.PostMultipart(link,m,Null)

    Wait For (j) JobDone(j As HttpJob)
    
    If j.Success=True Then
        Log(j.getstring)
        Log("success")
        j.Release
    Else
        'do something'
        Log("ugh")
        j.Release
    End If

    
End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
According to the link I used above, they use "api-key" in the code samples

Update:
Actually it's from their developer docs here: https://developer.nexmo.com/api/sms . There they use api-key, in the sample for CURL, they use api_key. Confusing
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
That is not at all the same as the CURL command you first posted. Does it work with CURL like you have in post #1? With this CURL, you are encoding the api_key into the URL. Looking at the code for PHP, they are making the username/password for BASIC authentication the api key/secret. How confusing is that. So set username/password of the HttpJob variable to api_key/api_secret values and see what happens.

Link:

P.S.: I would not make api_key/secret part of the URL. URL's are frequently logged. SSL can limit who can log, but they are still logged and often in plain text
 
Upvote 0

AKJammer

Active Member
Licensed User
Yeah, I was experimenting. The first curl is the one I initially ran that worked. Was reading the man page on curl and discovered they were items separated by &'s so tried that as well. Didn't know about the logging, so yeah, that'd be a bad thing...


Same error when loading the job username and password
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
I think I found your error. Take the ? of the poststring, otherwise the other end expects something on the URL.
so
B4X:
j.poststring("https://rest.nexmo.com/sms/json?",json.ToString )
should be
B4X:
j.poststring("https://rest.nexmo.com/sms/json",json.ToString )
PostString sends the JSON structure in the body of the request to the server, not the URL. Having the ? at the end, the server thinks there are parameters. Since api_key does not show up in the parameter list (even though its in the JSON structure), the server complains (looks like parameters on the URL have priority over parameters in the body of the request). I don't think you have to set username/password of the HttpJob variable.
 
Upvote 0

AKJammer

Active Member
Licensed User
Yeah, that was another experiment. I tried with and without the ?, same error.

arghh.. majorly frustrating. I know it's got to be something stupid I'm doing. I really appreciate your patience.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
B4X:
j.PostString(...)
j.GetRequest.SetContentType("application/x-www-form-urlencoded")
 
Upvote 0

AKJammer

Active Member
Licensed User
DonManfred, Same error. I tried changing back to postmultipart with adding the j.getrequest.setcontentype but it blew up (Request does not support this method)
With j.Poststring, it doesn't blow up, just gives same error back Missing api_key.

Here's what the current sub looks like now. experiments are commented out...

B4X:
Sub vonage (Phone As String, Message As String)

'curl -X "POST" "https://rest.nexmo.com/sms/json" \
'   -d "from=15558889999" \
'   -d "api_key=xxxxxx" \
'   -d "api_secret=yyyyyyyyyy" \
'    -d "to=15552279966" \
'    -d "text=You are Registered in 3 contests with Bib 982"

    Dim m As Map
    m.Initialize
    m.Put("from", myFromNumber)
    m.Put("api_secret", txtSecret.text)
    m.Put("to", Phone)
    m.Put("text", Message)
    m.Put("api_key", txtKey.text)

    Dim json As JSONGenerator
    json.initialize(m)
    
    Dim stringtosend As String = json.ToString
    
    Log(stringtosend)

    Dim j As HttpJob
    j.Initialize("", Me)
'    j.Username=txtKey.Text
'    j.Password=txtSecret.text
    Dim link As String = "https://rest.nexmo.com/sms/json"
    j.poststring(link,json.ToString )
    j.GetRequest.SetContentType("application/x-www-form-urlencoded")
    
'    j.PostMultipart(link,m,Null)
'    j.PostBytes(link, stringtosend.GetBytes("utf-8"))

    Wait For (j) JobDone(j As HttpJob)
    
    If j.Success=True Then
        Log(j.getstring)
        Log("success")
        j.Release
    Else
        'do something'
        Log("ugh")
        j.Release
    End If

    
End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Ok, I read the API totally wrong. The json at the end of the URL is not for how the data is sent, but for how the servers response is encoded. The actual data sent to the server needs to be application/x-www-form-urlencoded. It's right there in the docs (see https://developer.nexmo.com/api/sms), right next to the word Request body. So you need to create a string of key1=value1&key2=value2&key3=value3 and so on. It is that string that you post to the server via PostString. Plus you need to set the header as per @DonManfred.

Update: BTW, that's exactly what the CURL statement in post#1 is doing. What a reading comprehension failure on my part. Ugh.
 
Upvote 0

AKJammer

Active Member
Licensed User
Ahhh, Success. I thought I'd tried this near the beginning, and I might have but had a different error since I didn't have the j.getstring yet.

Thanks a lot guys for the assistance.

Here's the final sub showing the CURL and the httpjob for anyone looking in the future.

B4X:
Sub vonage (Phone As String, Message As String)

'curl -X "POST" "https://rest.nexmo.com/sms/json" \
'   -d "from=15558889999" \
'   -d "api_key=xxxxxx" \
'   -d "api_secret=yyyyyyyyyy" \
'    -d "to=15552279966" \
'    -d "text=You are Registered in 3 contests with Bib 982"

    Dim stringtosend As String = $"from=${myFromNumber}&api_key=${txtKey.Text}&api_secret=${txtSecret.Text}&to=${Phone}&text=${Message}"$
    
    Dim j As HttpJob
    j.Initialize("", Me)
    Dim link As String = "https://rest.nexmo.com/sms/json"
    j.poststring(link,stringtosend )

    Wait For (j) JobDone(j As HttpJob)
    
    If j.Success=True Then
        Log(j.getstring)
        Log("success")
        j.Release
    Else
        'do something'
        Log("ugh")
        j.Release
    End If

    
End Sub
 
Upvote 0
Top