Question
· Dec 14, 2023

How can I send a file through Form Data in a REST HTTP Request?

Hello everyone!
I have to build a REST service that receives a POST HTTP-request, collect a file from that request in the Form data and then send it in another HTTP Post request through Form Data. However I can't really seem to send the file, and I do not know where it has gone wrong. All I am getting told is that no file is being received from my HTTP Post request. I am reaching the REST Service I am supposed to send the request to, but nothing is being sent.

I would be really thankful if someone could give some insight why nothing is being sent in my request. Thanks beforehand! :)

So, this is my REST-Service that receives the HTTP request:

XData UrlMap [ XMLNamespace = "https://www.intersystems.com/urlmap]
{
<Routes>
<Route Url="/TEST" Method="POST" Call="PostHandler" />
</Routes>
}

ClassMethod PostHandler() As %Status
{

set vProfile = %request.Get("profile")

set vFilen = %request.GetMimeData("file")

set classToPostHandler = ##class(Classes.PostClass).%New()

set classToPostHandler.Profile = vProfile

set classToPostHandler.file = vFilen

set status = ##class(Ens.Director).CreateBusinessService("PostHandlerService", .instance)
    #dim response as %DynamicObject
    
    set status = instance.OnProcessInput(classToPostHandler, .response)
    
   if $ISOBJECT(response)
{          Do ##class(%REST.Impl).%SetContentType("application/json; charset=utf-8")
       Do ##class(%REST.Impl).%SetStatusCode("200")
       Do ##class(%REST.Impl).%WriteResponse(response)

       Quit $$$OK
}else
{
Do ##class(%REST.Impl).%SetStatusCode("500")
write "ERROR"
} Quit $$$OK

}

Underneath is my class that is used to transfer "vProfile" and "vFilen" to the Business Service that executes the HTTP Post request:

Class Classes.PostClass Extends %Persistent
{

Property Profile As %String;

Property file As %Stream.FileBinary;

}

Underneath here is the Business Service that executes the HTTP Post request:

Method OnProcessInput(pInput As Classes.PostClass, Output pOutput As %RegisteredObject) As %Status
{
set profile = pInput.Profile

set filen = pInput.file 

set request = ##class(%Net.HttpRequest).%New()
set request.Server = "placeholderurl.url"
set request.ContentType = "multipart/form-data;"
Do request.SetHeader("Accept", "*/*")
Do request.SetHeader("Accept-Encoding","gzip, deflate, br")

Do request.InsertFormData("profile", profile)
Do request.InsertFormData("file",filen) 

set tsc = request.Post("placeholderendpoint")


set response = request.HttpResponse.Data

set code = request.HttpResponse.StatusCode
$$$LOGINFO(response)
$$$LOGINFO(code)
set pOutput = response
Quit $$$OK
}else
{
$$$LOGINFO("ERROR")
}
} Quit $$$OK
}

}

Product version: IRIS 2023.3
Discussion (6)3
Log in or sign up to continue

Having just done the same thing today, following Marc's comment (which is the same code in the documentation for MIMEParts) should get you what you need.

As it stands, I'm pretty sure you are just passing a handle to a stream to the FormData, rather than referencing the content of the stream.  This section of the example will correctly populate the HTTP Request body:

  // Write out Root MIME Element (containing sub-MIME parts) to HTTP Request Body.
    Set writer = ##class(%Net.MIMEWriter).%New()
    Set sc = writer.OutputToStream(tHttpRequest.EntityBody)
    if $$$ISERR(sc) {do $SYSTEM.Status.DisplayError(sc) Quit}
    Set sc = writer.WriteMIMEBody(rootMIME)
    if $$$ISERR(sc) {do $SYSTEM.Status.DisplayError(sc) Quit}