Curl POST

Hello,

I’m using an old RealStudio 2011 release to update some features for an old project and I’m facing some issues with using a curl request.
I want to use an online OCR API, which can be called with a curl request.
The example on the site looks like this:

curl -X POST \\
  https://api.mindee.net/v1/products/mindee/invoices/v4/predict \\
  -H 'Authorization: Token my-api-key-here' \\
  -H 'content-type: multipart/form-data' \\
  -F document=@/path/to/your/file.png

I try to use it in the project like this in a pushbutton action event:

  Dim d As New Dictionary
   
  // This service simply returns the post data as the result
  Dim result As String

  result = Socket.Post("curl -X POST 'https://api.mindee.net/v1/products/mindee/invoices/v4/predict' -H 'Authorization: myAPIkey' -H 'content-type: multipart/form-data' -F document=@d:/DOWNLOAD/fact.pdf", 30)
  
  result = DefineEncoding(result, Encodings.UTF8)
  
  MsgBox(result)

Socket is a HTTPSocket.

I get a response of “400 Bad Request”.

What am I doing wrong?

Please goggle on how to use curl with Xojo. Curl is a library. See for instance MBS Xojo Blog - Starting with CURL functions .

The example is using the curl command line tool. If you have that installed then you could call it via the Realbasic Shell.

You are extremely lucky in that this API is responding to HTTP/1.0 requests, otherwise RealStudio 2011 would be too old to use at all.

You don’t really need cURL plugins to do this. One simply has to understand what the example the API provider gave means.

-H means it’s a header, so supply that with HTTPSecureSocket.SetRequestHeader("Authorization", "Token {key}")
-F and the content-type “multipart/form-data” means the body of the request is formatted as multipart/form-data, for which there is really old HTTPSocket code floating around.

If (and probably soon) this API updates their server security to reject HTTP/1.0 or outdated TLS v1, you will not be able to use RealStudio 2011 and would actually be forced to use a plugin. It would be wise to update to a modern version of Xojo.

1 Like

Thank you for your reply.
I tried it, but something I still don’t do it in the right way.
My code is

  
  // This service simply returns the post data as the result
  Dim result As String

  Socket.SetRequestHeader("Authorization", "mykey")
  Socket.SetRequestHeader("content-type", "multipart/form-data")
  
  dim f as FolderItem = GetFolderItem("d:/DOWNLOAD/fact.pdf")
  if f<>NIL  then
    Dim HTMLForm As New Dictionary
    HTMLForm.Value("Upload") = f.AbsolutePath
     SetFormData(Socket, HTMLForm, "") ' pass an empty boundary to generate a new one
    result = Socket.Post("https://api.mindee.net/v1/products/mindee/invoices/v4/predict", 30)
       
    result = DefineEncoding(result, Encodings.UTF8)
    
    TextArea1.Text=""
    TextArea1.Text=result
  else
    MsgBox "NO FILE"
  end if

I get response "308 Permanent Redirect"

the SetFormData looks like this:

Sub SetFormData(sock As HTTPSocket, FormData As Dictionary, Boundary As String)
  If Boundary.Trim = "" Then
    Boundary = "--" + Right(EncodeHex(MD5(Str(Microseconds))), 24) + "-bOuNdArY"
  End If
  
  Static CRLF As String = EndOfLine.Windows
  Dim data As New MemoryBlock(0)
  Dim out As New BinaryStream(data)
  
  For Each key As String In FormData.Keys
    out.Write("--" + Boundary + CRLF)
    If VarType(FormData.Value(Key)) = Variant.TypeString Then
      out.Write("Content-Disposition: form-data; name=""" + key + """" + CRLF + CRLF)
      out.Write(FormData.Value(key) + CRLF)
    ElseIf FormData.Value(Key) IsA FolderItem Then
      Dim file As FolderItem = FormData.Value(key)
      out.Write("Content-Disposition: form-data; name=""" + key + """; filename=""" + File.Name + """" + CRLF)
      out.Write("Content-Type: application/octet-stream" + CRLF + CRLF) ' replace with actual MIME Type
      Dim bs As BinaryStream = BinaryStream.Open(File)
      out.Write(bs.Read(bs.Length) + CRLF)
      bs.Close
    End If
  Next
  out.Write("--" + Boundary + "--" + CRLF)
  out.Close
  #If RBVersion > 2012 Then
    sock.SetRequestContent(data, "multipart/form-data; boundary=" + Boundary)
  #else
    sock.SetPostContent(data, "multipart/form-data; boundary=" + Boundary)
  #endif
End Sub

Are you sure that the url is the correct one? Why do you save data to a folderitem just to read the data again? You can completely remove the folderitem.

#1

Probably should be

Socket.SetRequestHeader("Authorization", "Token mykey")

Note the word “Token” before your key.


#2

This is incorrect. Put the FolderItem itself in the dictionary, not the path:

HTMLForm.Value("Upload") = f


#3

The URL is HTTPS. Try changing HTTPSocket to HTTPSecureSocket.


#4

This line is not needed. Delete it.

2 Likes

Hello

It is getting better and better. I made the modifications Andrew suggested, but I now have this error:
400 The plain HTTP request was sent to HTTPS port

Are you using HTTPSecureSocket with the Secure property set to true?

Also be sure you’re using Socket.ConnectionType = SSLSocket.TLSv1, as that is the most secure protocol RealStudio 2011 can offer.

Thank you Tim,

Now I don’t get any error response. But neither else.
I get back an empty result.

Here is the code:

  Dim result As String
  
  Socket.ConnectionType=SSLSocket.TLSv1
  Socket.Secure=True
  Socket.SetRequestHeader("Authorization", "Token a3d265458e4a9365384090e068f68b68")
  
  dim f as FolderItem = GetFolderItem("d:/DOWNLOAD/fact.pdf")
  if f<>NIL  then
    Dim HTMLForm As New Dictionary
    
    HTMLForm.Value("document") = f
     SetFormData(Socket, HTMLForm, "") ' pass an empty boundary to generate a new one
    result = Socket.Post("https://api.mindee.net/v1/products/mindee/invoices/v4/predict", 30)
    
    result = DefineEncoding(result, Encodings.UTF8)
    
    TextArea1.Text=""
    TextArea1.Text=result
  else
    MsgBox "NO FILE"
  end if

I feel that something small is still missing.

It’s possible (even likely) that the API refuses to accept the older versions of TLS that are supported in RS2011. In which case, the server would terminate the connection attempt before it was complete, which would appear as a silent failure on your end.

Maybe try Socket.ConnectionType=SSLSocket.SSLv23. Otherwise, you may need a newer version of Realstudio; 2014r2 was the last update to the HTTPSecureSocket, which included newer TLS versions.

I agree, but what confuses me is that I would have expected the dropped connection prior to getting error response JSON for the other requests.

Thank you for the huge help.
I will try to ask more on Mindee’s support forum.