Question
Yone Moreno · Jan 4, 2021

Send an image as a multi part File

Hello,

We would like some advice

We have developed a REST Operation

The code is:

Class Operaciones.REST.miSCS.miSCS Extends EnsLib.REST.Operation
{

Parameter INVOCATION = "Queue";

/// 📤 Subir la imagen del usuario
Method SubirImagen(pRequest As Mensajes.Request.miSCS.SubirImagen, pResponse As Mensajes.Response.miSCS.SubirImagen) As %Library.Status
{
    set httpRequest = ##class(%Net.HttpRequest).%New()
    set tResponse = ##class(%Net.HttpResponse).%New()
    //set httpRequest.ContentType = "application/json"
    set httpRequest.ContentType = "multipart/form-data"

    
    set url      = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","url")
    set path     = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","path")
    set servicio = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","servicio")
    set recurso  = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","subirImagen")
            
    set URL = "http://"_url_path_servicio_recurso
    $$$LOGINFO("URL: "_URL)
    
    /*
    //Probamos a leer una imagen local y a enviarla
    
    Set stream=##class(%Stream.FileCharacter).%New()
      Set sc=stream.LinkToFile("Pictures\mi.jpg")
      While 'stream.AtEnd {
          Set linea=stream.Read()
      }
      $$$LOGINFO("linea: "_linea)
      */
    
    set tFormVarNames = "expediente,imagen"
    set tData("expediente") = pRequest.expediente
    set tData("imagen") = pRequest.imagen
    //set tData("imagen") = linea

    set tSC = ..Adapter.SendFormDataArray(.tResponse,"POST",httpRequest,.tFormVarNames,.tData,URL)
    $$$LOGINFO("tSC: "_tSC)
    
    if $$$ISERR(tSC){
            $$$ThrowOnError(tSC)
    }
    if (tResponse.Data.AtEnd = 0) {
        $$$LOGINFO("En SubirImagen, tamaño de tResponse: "_tResponse.Data.Size)
        set linea = tResponse.Data.Read()
        $$$LOGINFO("Linea: "_linea)
    }
    
    set pResponse = ##class(Mensajes.Response.miSCS.SubirImagen).%New()
    do pResponse.return.Write(linea)

    Quit pResponse
}

XData MessageMap
{
<MapItems>
  <MapItem MessageType="Mensajes.Request.miSCS.SubirImagen">
    <Method>SubirImagen</Method>
  </MapItem>

</MapItems>
}

When we send the request from the Production testing the Operation we get the following exception:

ERROR <Ens>ErrException: <THROW>zSubirImagen+27^Operaciones.REST.miSCS.miSCS.1 *%Exception.StatusException ERROR <Ens>ErrHTTPStatus: Received non-OK status 500 from remote HTTP server: 'HTTP/1.1 500 ' -- logged as '-' number - @' Set sc=tSC Throw:('sc) ##class(%Exception.StatusException).ThrowIfInterrupt(sc)'

 

Using POSTMAN directly to the endpoint we observe the following in Whireshark:

> As you would notice we see that the image is being sent as a multipart file, so then it is correct because the endpoint replies to us.

 

When we capture the request sent with Ensemble we see:

Here we observe that the image is being sent as text.

 

How could we send an image as a multi part File, using a REST Operation in Ensemble?

 

Could you help us? Could you provide some code example, please?

 

Thanks in advance

 

We have read:

https://docs.intersystems.com/latest/csp/docbook/Doc.View.cls?KEY=EREST_...

https://community.intersystems.com/post/polling-external-rest-api-ensemble

https://community.intersystems.com/post/how-send-file-json

https://community.intersystems.com/post/send-json-http-request

https://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?...

https://docs.intersystems.com/latest/csp/docbook/Doc.View.cls?KEY=GOBJ_p...

 

 

00
2 0 5 79

Replies

Hello,

Thanks Marc Mundt for your help,

1 We have tried with the following code which reads a String which represents an image in pRequest.imagen and we send it into a MIME:

Class Operaciones.REST.miSCS.miSCSSubirImagenJPGlocal Extends EnsLib.REST.Operation { Parameter INVOCATION = "Queue";

/// 📤 Subir la imagenSanitaria
Method SubirImagen(pRequest As Mensajes.Request.miSCS.SubirImagen, pResponse As Mensajes.Response.miSCS.SubirImagen) As %Library.Status
{
    
    Set httpRequest=##class(%Net.HttpRequest).%New()
    set tResponse = ##class(%Net.HttpResponse).%New()
    
    Set msg=##class(%Net.MIMEPart).%New()
     Set msg.Body=##class(%GlobalCharacterStream).%New()
    Do msg.Body.Write(pRequest.imagen)
    Set msg.ContentType="multipart/form-data"
    
    // create MIME writer; write root MIME message
    Set writer=##class(%Net.MIMEWriter).%New()

    // Prepare outputting to the HttpRequestStream
    Set status=writer.OutputToStream(httpRequest.EntityBody)
    if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit}

    // Now write down the content
    Set status=writer.WriteMIMEBody(msg)
    if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit}
    
    set url      = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","url")
    set path     = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","path")
    set servicio = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","servicio")
    set recurso  = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","subirImagen")
            
    set URL = "http://"_url_path_servicio_recurso
    $$$LOGINFO("URL: "_URL)

    set tFormVarNames = "expediente,imagen"
    set tData("expediente") = pRequest.expediente
    set tData("imagen") = pRequest.imagen

    set tSC = ..Adapter.SendFormDataArray(.tResponse,"POST",httpRequest,.tFormVarNames,.tData,URL)
    $$$LOGINFO("tSC: "_tSC)
    
    if $$$ISERR(tSC){
            $$$ThrowOnError(tSC)
    }
    if (tResponse.Data.AtEnd = 0) {
        $$$LOGINFO("En SubirImagen, tamaño de tResponse: "_tResponse.Data.Size)
        set linea = tResponse.Data.Read()
        $$$LOGINFO("Linea: "_linea)
    }
    
    set pResponse = ##class(Mensajes.Response.miSCS.SubirImagen).%New()
    do pResponse.return.Write(linea)

    Quit pResponse
}

However when we see it using Whireshark we observe that it is being sent as text/html

2 We have also used the following approach, to read a JPG directly and send it into the MIME:

Class Operaciones.REST.miSCS.miSCSSubirImagenJPGlocal Extends EnsLib.REST.Operation
{

Parameter INVOCATION = "Queue";

/// 📤 Subir la imagenSanitaria
Method SubirImagen(pRequest As Mensajes.Request.miSCS.SubirImagen, pResponse As Mensajes.Response.miSCS.SubirImagen) As %Library.Status
{
    
    //Crear Request y Response HTTP
    Set httpRequest=##class(%Net.HttpRequest).%New()
    set tResponse = ##class(%Net.HttpResponse).%New()
    
    //Crear MIME
    Set msg=##class(%Net.MIMEPart).%New()
     Set msg.Body=##class(%GlobalCharacterStream).%New()
     
    //Probamos a leer una imagen local y a enviarla
    Set stream=##class(%Stream.FileCharacter).%New()
      Set sc=stream.LinkToFile("C:\Users\ext-ymorjim\Pictures\miSCS.jpg")
      While 'stream.AtEnd {
          Set linea=stream.Read()
      }
      $$$LOGINFO("linea: "_linea)
      
      //Escribir la imagen en el mensaje MIME
     Do msg.Body.Write(linea)
    //Do msg.Body.Write(pRequest.imagen)
    Set msg.ContentType="multipart/form-data"
    
    // create MIME writer; write root MIME message
    Set writer=##class(%Net.MIMEWriter).%New()

    // Prepare outputting to the HttpRequestStream
    Set status=writer.OutputToStream(httpRequest.EntityBody)
    if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit}

    // Now write down the content
    Set status=writer.WriteMIMEBody(msg)
    if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit}
    

    set url      = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","url")
    set path     = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","path")
    set servicio = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","servicio")
    set recurso  = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","subirImagen")
            
    set URL = "http://"_url_path_servicio_recurso
    $$$LOGINFO("URL: "_URL)

    set tFormVarNames = "expediente,imagen"
    set tData("expediente") = pRequest.expediente
    set tData("imagen") = pRequest.imagen
    //set tData("imagen") = linea

    set tSC = ..Adapter.SendFormDataArray(.tResponse,"POST",httpRequest,.tFormVarNames,.tData,URL)
    $$$LOGINFO("tSC: "_tSC)
    
    if $$$ISERR(tSC){
            $$$ThrowOnError(tSC)
    }
    if (tResponse.Data.AtEnd = 0) {
        $$$LOGINFO("En SubirImagen, tamaño de tResponse: "_tResponse.Data.Size)
        set linea = tResponse.Data.Read()
        $$$LOGINFO("Linea: "_linea)
    }
    
    set pResponse = ##class(Mensajes.Response.miSCS.SubirImagen).%New()
    do pResponse.return.Write(linea)

    Quit pResponse
}

With the previous code we see that a text/html is being sent too:

In both cases, the external system gives us a HTTP code 400:

     ERROR <Ens>ErrException: <THROW>zSubirImagen+40^Operaciones.REST.miSCS.miSCS.1 *%Exception.StatusException ERROR <Ens>ErrHTTPStatus: Received non-OK status 400 from remote HTTP server: 'HTTP/1.1 400 ' -- logged as '-' number - @' Set sc=tSC Throw:('sc) ##class(%Exception.StatusException).ThrowIfInterrupt(sc)'

How could we achieve to send it in the correct way? as it is being sent when we use POSTMAN:

How could we send the image as multipart/form-data?

> We have read:

https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI...

https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.c...

How could we send the image as multipart/form-data as it is being sent by Postman?

➡️ Could you point us to same code examples, please?

Hello,

We have continued the development,

The output system now replies to us

However we do see that the 2nd MIME part, the image, is being sent from ENSEMBLE, different than the image sent with POSTMAN

1 Let's see what we send from Ensemble:

2 The following image show us what POSTMAN correctly sends:

If we examine and compare both images, we observe that the image sent with Postam is being recognized as a JPEG, however the one sent with Ensemble is not being sent as a JPEG

The code which we have written is:

Class Operaciones.REST.miSCS.miSCS Extends EnsLib.REST.Operation
{

Parameter INVOCATION = "Queue";

/// 📤 Subir la imagen 
Method SubirImagen(pRequest As Mensajes.Request.miSCS.SubirImagen, pResponse As Mensajes.Response.miSCS.SubirImagen) As %Library.Status
{
    
    //Crear Request y Response HTTP
    Set httpRequest=##class(%Net.HttpRequest).%New()
    set tResponse = ##class(%Net.HttpResponse).%New()
    
    // Create root MIMEPart, la parte que contiene al resto
    Set RootMIMEPart=##class(%Net.MIMEPart).%New()
    
    //Crear parte con el expediente
     Set ExpedienteMIMEPart=##class(%Net.MIMEPart).%New()
     Set contentdisp="form-data; name=""expediente"""
     Do ExpedienteMIMEPart.SetHeader("Content-Disposition",contentdisp)
     Set ExpedienteMIMEPart.Body=pRequest.expediente
     //Do ExpedienteMIMEPart.SetHeader("Content-Type","text/plain")
     
    // Crear parte con la imagen
    Set ImagenMIMEPart=##class(%Net.MIMEPart).%New()
    Set ImagenMIMEPart.Body=##class(%GlobalCharacterStream).%New()
    //Probamos a leer una imagen local
    Set stream=##class(%Stream.FileCharacter).%New()
      Set sc=stream.LinkToFile("C:\Users\ext-ymorjim\Pictures\miSCS.jpg")
      While 'stream.AtEnd {
          Set linea=stream.Read()
      }
      $$$LOGINFO("linea: "_linea)
      //Escribir la imagen en el mensaje MIME
     Do ImagenMIMEPart.Body.Write(linea)
    //Do ImagenMIMEPart.Body.Write(pRequest.imagen)

    // Cabeceras de la imagen
    Set ImagenMIMEPart.ContentType="image/jpeg"
    Set contentdisp="form-data; name=""imagen""; filename="""_stream.Filename_""
    Do ImagenMIMEPart.SetHeader("Content-Disposition",contentdisp)

    // Insertar las partes en la raiz
    Do RootMIMEPart.Parts.Insert(ExpedienteMIMEPart)
    Do RootMIMEPart.Parts.Insert(ImagenMIMEPart)
    
    // create MIME writer; write root MIME message
    Set writer=##class(%Net.MIMEWriter).%New()

    // Prepare outputting to the HttpRequestStream
    Set httpRequest=##class(%Net.HttpRequest).%New()
    Set status=writer.OutputToStream(httpRequest.EntityBody)
    if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit}

    // Now write down the content
    Set status=writer.WriteMIMEBody(RootMIMEPart)
    if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit}

    // Creamos la URL
    set url      = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","url")
    set path     = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","path")
    set servicio = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","servicio")
    set recurso  = ##class(Util.TablasMaestras).getValorMaestra("MISCS.PARAMETRIZACIONES","subirImagen")
            
    set URL = "http://"_url_path_servicio_recurso
    $$$LOGINFO("URL: "_URL)
    
    
    //Escribimos el tipo de contenido que enviamos
    Set httpRequest.ContentType="multipart/form-data; boundary="_RootMIMEPart.Boundary
    $$$LOGINFO("> httpRequest.ContentType: "_httpRequest.ContentType)
    
    //Enviamos
    set tSC=httpRequest.Post(URL,0)
    $$$LOGINFO("tSC: "_tSC)
    
    if $$$ISERR(tSC){
            $$$ThrowOnError(tSC)
    }
    if (tResponse.Data.AtEnd = 0) {
        $$$LOGINFO("En SubirImagen, tamaño de tResponse: "_tResponse.Data.Size)
        set linea = tResponse.Data.Read()
        $$$LOGINFO("Linea: "_linea)
    }
    
    set pResponse = ##class(Mensajes.Response.miSCS.SubirImagen).%New()
    set pResponse.resultado = 1
    set pResponse.informacion = linea

    Quit pResponse
}

How could we continue
 

Could you point us to some example??, please

We have read:

https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI...

Thanks in advance

Hi Yone,

I see two possible problems:

It seems like "Do ImagenMIMEPart.Body.Write(linea)" should be inside the while loop. No? In this case after the final read() linea may be empty and that is what is set as the content of the mime part.

While 'stream.AtEnd {
          Set linea=stream.Read()
      }
      $$$LOGINFO("linea: "_linea)
      //Escribir la imagen en el mensaje MIME
     Do ImagenMIMEPart.Body.Write(linea)

And here you are using a character stream to read the jpeg, but jpeg is a binary format. You'll want to use %Stream.FileBinary instead.

Set stream=##class(%Stream.FileCharacter).%New()
      Set sc=stream.LinkToFile("C:\Users\ext-ymorjim\Pictures\miSCS.jpg")