Thanks Jeffrey for your kind help, and thanks for your time.

We have wrote your method in a class called "Util.FuncionesComunes"

Namespace "ESBSSCC"

We have wrote in the terminal:

ESBSSCC 2e1>Set hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Producion.ESBSSCC","EnsLib.HTTP.InboundAdapter")
 

We observe:


SET hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Produccion.ESBSSCC",
^
"EnsLib.HTTP.InboundAdapter")
<COMMAND>^Util.FuncionesComunes.1

ESBSSCC 2e1>

Production's name is: Producion.ESBSSCC

How could we debug this to be able to execute the code and list all REST services in the current namespace?

Thanks for your help, time and replies Jeffrey

Thanks Jeffrey

We have placed your function in a class called "Util.FuncionesComunes"

We have tried to execute it as follows:

Set hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Produccion.ESBSSCC","EnsLib.HTTP.InboundAdapter")

It shows:

SET hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Produccion.ESBSSCC",
^
"EnsLib.HTTP.InboundAdapter")
<COMMAND>^Util.FuncionesComunes.1

When we write: "w $ZERROR" it outputs:

SET hosts=##class(Util.FuncionesComunes).GetHostsByAdapter("Produccion.ESBSSCC",
^
"EnsLib.HTTP.InboundAdapter")
<COMMAND>^Util.FuncionesComunes.1

How could we solve this?

Hello Marc Mundt,

ITB.HL7.BS.XMLService code is the following:

/// HL7 XML services common class
Class ITB.HL7.BS.XMLService Extends (Ens.BusinessService, ITB.HL7.XMLHost)
{

/// Location and Revision of this file in Perforce (Auto-updating)
Parameter SrcVer = "$Id$";

Property UseAckCommitCodes As %Boolean [ InitialExpression = 1 ];

Property BadMessageHandler As %String(MAXLEN = 1000);

/// Name of the element to send the incoming XML stream received by this Service if message is processed OK
Property XMLInputHandler As %String(MAXLEN = 1000);

/// Colon-separated LocalFacility:LocalApplication:MessageStructure codes representing this (receiving) facility, application, returning MessageStructure, AcceptAcknowledgmentType and ApplicationAcknowledgmentType<br/>
/// These are used in constructing reply ACK message headers as SendingFacility, SendApplication and MessageStructure. <br/>
/// The '@' symbol represents using the corresponding field from the incoming message. <br/>
/// If your ID must contain a literal @ symbol, escape it with backslash: '\@'
Property LocalFacilityApplication As %String [ InitialExpression = "ISC:EnsembleHL7:ACK:NE:NE" ];

/// Strip namespace in HL7 XML (ACK message).
Property StripNamespace As %Boolean [ InitialExpression = 1 ];

/// Control of ACK handling; options: <br/>
/// - Never : Do not send back any ACK <br/>
/// - Immediate : Send back (commit) ACK reply message immediately upon receipt of the inbound message <br/>
/// - Application : If message passes validation, wait for ACK from target config item and forward it back when it arrives <br/>
Property AckMode As %String(DISPLAYLIST = ",Never,Immediate,Application", VALUELIST = ",Never,Immed,App") [ InitialExpression = "Immed", Required ];

/// Names the target(s) from which an ACK response should be forwarded back to the caller, if the AckMode="Application".
Property ResponseFrom As %String(MAXLEN = 1000);

Parameter SETTINGS = "StripNamespace,LocalFacilityApplication,AckMode,ResponseFrom::selector?context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},UseAckCommitCodes,TargetConfigNames:Basic:selector?multiSelect=1&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},BadMessageHandler:Basic:selector?context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},XMLInputHandler:Basic:selector?context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId},SearchTableClass::selector?context={Ens.ContextSearch/SearchTableClasses?host=EnsLib.HL7.Service.Standard},MessageSchemaCategory:Basic:selector?context={Ens.ContextSearch/SchemaCategories?host=EnsLib.HL7.Service.Standard},AlertGracePeriod:Alerting";

/// HL7 XML (Stream) process input
Method StreamProcessInput(pInput As %Stream.Object, Output pOutput As %Stream.Object, pSendAck As %Boolean = 0, pCallTargets As %Boolean = 1, Output pER7 As EnsLib.HL7.Message) As %Status
{
    set ret = $$$OK
    
    try {
        // convert XML input to ER7
        set tER7 = ##class(ITB.HL7.Util.Convert).XMLToER7(pInput,.tSC,..MessageSchemaCategory)
        if $$$ISERR(tSC) $$$ThrowStatus(tSC)
        set pER7 = tER7
        
        // send ACK
        if pSendAck,..AckMode="Immed" {
            set tAckCode = $case(..UseAckCommitCodes, 1:"CA", 0:"AA")
            set tAckER7 = ..GetAck(tER7, tAckCode)
            set tAckXML = ##class(ITB.HL7.Util.Convert).ER7ToXML(tAckER7,.tSC,,,,..StripNamespace)
            if $$$ISERR(tSC) $$$ThrowStatus(tSC)
            set pOutput = tAckXML
        }
        
        // send EnsLib.HL7.Message to targets
        if pCallTargets {
            for i=1:1:$l(..TargetConfigNames, ",") {
                set tTarget=$zstrip($p(..TargetConfigNames,",",i),"<>W")
                if pSendAck,..AckMode="App",..ResponseFrom=tTarget {
                    $$$THROWONERROR(tSC,..SendRequestSync(tTarget, tER7, .tAckER7))
                    set tAckXML = ##class(ITB.HL7.Util.Convert).ER7ToXML(tAckER7,.tSC,,,,..StripNamespace)
                    if $$$ISERR(tSC) $$$ThrowStatus(tSC)
                    set pOutput = tAckXML
                } else {
                    $$$THROWONERROR(tSC,..SendRequestAsync(tTarget, tER7))
                }
            }
        }
        
        // index HL7 in SearchTable
        if ..SearchTableClass'="" {
            set tSC = $zobjclassmethod(..SearchTableClass,"IndexDoc",tER7)
            if $$$ISERR(tSC) $$$LOGERROR("SearchTableClass Error: "_##class(%SYSTEM.Status).GetErrorText(tSC))
        }
        
        // ok. send XML input to XMLInputHandler if any
        do:..XMLInputHandler'="" ..SendStreamToTarget(..XMLInputHandler,pInput)
        
    } catch ex {
        set ret = ex.AsStatus()
        $$$LOGERROR($$$StatusDisplayString(ret))
        
        // error occured. send service input to BadMessageHandler if any
        do:..BadMessageHandler'="" ..SendStreamToTarget(..BadMessageHandler,pInput)
        
        // send alert when HL7 XML has not been processed correctly
        do:..AlertOnError ..SendAlert(##class(Ens.AlertRequest).%New($LB(..%ConfigName,$$$StatusDisplayString(ret))))
    }
    
    quit ret
}

/// Get ACK message for a given HL7 message
Method GetAck(pMsg As EnsLib.HL7.Message, pReplyCode As %String) As EnsLib.HL7.Message
{
    // create ACK and copy the control id to the ack control id
    set tReply = pMsg.NewReplyDocument(,..LocalFacilityApplication)
    set tReply.Source = pMsg.%Id()
    do tReply.SetValueAt(pMsg.GetValueAt("1:10"),"1:10")
    do tReply.SetValueAt($p(..LocalFacilityApplication,":",3),"1:9.3")
    do tReply.SetValueAt($p(..LocalFacilityApplication,":",4),"1:15")
    do tReply.SetValueAt($p(..LocalFacilityApplication,":",5),"1:16")
    
    // MSA segment
    set tMSA=##class(EnsLib.HL7.Segment).%New($LB("",1))
    set tMSA.Separators=tReply.Separators
    do tMSA.SetValueAt("MSA",0)
    do tMSA.SetValueAt(pReplyCode,1)
    do tMSA.SetValueAt(pMsg.GetValueAt("1:10"),2)
    do tReply.AppendSegment(tMSA)
    
    quit tReply
}

/// Send pInput stream to a production target
Method SendStreamToTarget(pTarget As %String, pInput As %Stream.Object) As %Status
{
    set tMsg = ##class(Ens.StreamContainer).%New(pInput)
    set tSC = ..SendRequestAsync(pTarget, tMsg)
    if $$$ISERR(tSC) $$$LOGERROR(##class(%SYSTEM.Status).GetOneErrorText((tSC)))
    quit tSC
}

/// Return an array of connections for drawing lines on the config diagram
ClassMethod OnGetConnections(Output pArray As %String, pItem As Ens.Config.Item)
{
    do ##super(.pArray,pItem)
    
    if pItem.GetModifiedSetting("TargetConfigNames",.tValue) {
        
        set:pItem.GetModifiedSetting("BadMessageHandler",.tBadMessageHandler) tValue=tValue_","_tBadMessageHandler
        set:pItem.GetModifiedSetting("XMLInputHandler",.tXMLInputHandler) tValue=tValue_","_tXMLInputHandler
        
        for i=1:1:$L(tValue,",") {
            set tOne=$zstrip($p(tValue,",",i),"<>W")
            continue:""=tOne
            set pArray(tOne)=""
        }
    }
}

}

GetAck is a "Method"

How should we call it using method syntax, Marc Mundt?

Thanks for your replies

Thanks Eduard for sharing this interesting piece of advice

Why would be better or recommended to use %CSP.REST directly, instead of EnsLib.REST.Service?

Are there any improvements if we use %CSP.REST?

Thanks for your reply

We are grateful Marc for your help,

Thanks for explaining how did you find the cause which was preventing to get the response in POSTMAN

Thanks Marc Mundt for your help

You are right

When we removed that line, the response is shown in POSTMAN:

Thanks four your help Marc

How did you know we should remove that line?

Thanks Marc Mundt for your attention, and your helpful reply

 
Our current code is:

When we dig deeper using Whireshark:

First, we find that the method in the example that uses GET, the retrievePerson, does answers with a JSON to POSTMAN, so it works:

GET request:

GET response:

In POSTMAN:

However,

Our custom method: consultarImagen which is a POST

Shows nothing in POSTMAN

Why?

POST request:

POST response:

In POSTMAN:

Could you help us?

Thanks for your replies

Thanks Marc Mundt for your reply

Yes you are right, we should use POST

We have changed it:

<Route Url="/consultarImagen" Method="POST" Call="consultarImagen"/>

However we do not see the response in POSTMAN:

And the headers are:

Content-Type: text/html

Content-Length: 0

CACHE-CONTROL: no-cache

PRAGAM: no-cache

We send the POST to the following URL:

http://localhost:19622/aplicaciones/scs/test/miscs/consultarImagen
 

Besides we observe the response message being converted from Ensemble object to JSON in the service:

We do see the Response Message from the Operation to the Service

Why we do not see the JSON being replied from the Service in POSTMAN?

How could we debug this behaviour?

Thanks for your replies

Thanks Marc Mundt for your help,

We have tried to make objetoSalida.binario as %Binary

Exactly we do the following:

1) We read the image as binary directly from the external system in the REST Operation:

set linea=""
    if (tResponse.Data.AtEnd = 0) {
        set linea = tResponse.Data.Read()
    }
    
    set pResponse.binario = linea
    
    $$$LOGINFO("pResponse.binario: "_pResponse.binario)

We observe the binary correctly written in the LOGINFO:

2) In the Service, we have a LOGINFO  before writing it to JSON

 $$$LOGINFO("objetoSalida.binario: "_objetoSalida.binario)        

 set tSC = claseAux.%WriteJSONStreamFromObject(.pOutput,.objetoSalida,,,,"aeloqtuw")

We see it correctly:

3) However when we convert it to JSON we see that there are strange characters like "\x00"

set tSC = claseAux.%WriteJSONStreamFromObject(.pOutput,.objetoSalida,,,,"aeloqtuw")

$$$LOGINFO("pOutput.Read(): "_pOutput.Read())

How would you recommend us to continue?

What documents or code examples would you study or write to handle this issue?

Thanks for your help

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