Published on InterSystems Developer Community (https://community.intersystems.com)

Home > Creating a RESTFul Service, why custom method does not return the expected JSON?

Question
Yone Moreno · Mar 5, 2021

Creating a RESTFul Service, why custom method does not return the expected JSON?

FIrst of all thank you for your time in reading this question and writing a response,

We would need some help,

-> Our objective is to control which method is being used in the service: GET POST PUT

We have tried to understand the example REST Service: Demo.REST.DirectoryService

 

After that we have tried to create our own custom rest service,

please take a few minutes to examine the following code:

 
Code
Class Servicios.REST.miSCS.Pruebas Extends EnsLib.REST.Service
{

Parameter ADAPTER = "EnsLib.HTTP.InboundAdapter";

Parameter EnsServicePrefix = "/aplicaciones/scs/test/miscs";

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>

<Route Url="/:personType/:keyfield/:keyval/:getfield" Method="GET" Call="retrievePerson"/>
<Route Url="/consultarImagen" Method="GET" Call="consultarImagen"/>

</Routes>
}

/// Retrieve
Method retrievePerson(pInput As %Library.AbstractStream, Output pOutput As %Stream.Object, pPersonType As %String, pKeyField As %String, pKeyVal As %String, pGetField As %String = "") As %Status
{
    Set tType=$ZConvert(pPersonType,"L")  Quit:$Case(tType,"employee":0, "person":0, :1) $$$ERROR($$$EnsErrGeneral,"Directory type "_..#EnsServicePrefix_"/"_tType_"/ not supported.")
    Set $E(tType)=$ZConvert($E(tType),"U")
    Set tKeyIn=pKeyField, tKey=$ZConvert(tKeyIn,"L")  Quit:$Case(tKey,"name":0, "ssn":0, :1) $$$ERROR($$$EnsErrGeneral,"Directory key "_..#EnsServicePrefix_"/"_tType_"/"_tKey_" not supported.")
    Set tKeyVal=$Replace($ZConvert(pKeyVal,"I","URL"),"'","''")
    Set tField=pGetField  Set:""=tField tField="*"  Quit:tField["," $$$ERROR($$$EnsErrGeneral,"Commas not allowed in selection field; found: .../"_tField)
    Set tNS=$Namespace

    Set tKeyWild=$Translate(pKeyVal,"*?","%_")
    Do:tKeyWild'=pKeyVal pOutput.Write("[")
    ZNSpace "SAMPLES"
    try {
        Set tSel=$S("*"=tField:"ID",1:tField)
        Set tSQL="SELECT "_tSel_$S("*"=tField||(tKey=tSel):"", 1:","_tKey)_$Case("ID",tKey:"",tSel:"",:",ID")_" FROM Sample."_tType_" WHERE "_tKey_" LIKE '"_tKeyWild_"'"
        //$$$LOGINFO("tSQL: "_tSQL)
        Set tRS=##class(%ResultSet).%New()
        Set tSC=tRS.Prepare(tSQL)  Quit:$$$ISERR(tSC)
        Set tSC=tRS.Execute()  Quit:$$$ISERR(tSC)
        Set tFirst=1
        Set tOut=##class(%IO.StringStream).%New()
        While tRS.Next(.tSC) && $$$ISOK(tSC) {
            #; first normalize the case of the key and sel property names
            If tFirst {
                Set k="" For { Set k=$O(tRS.Data(k))  Quit:""=k
                    If $ZConvert(k,"L")=$Zconvert(tSel,"L") Set tSelN=k
                    If $ZConvert(k,"L")=$Zconvert(tKey,"L") Set tKeyN=k
                }
            }
            If $Case(tSelN, "Company":1, "Notes":1, "Home":1, "Office":1, :0) {
                Set tVal=tRS.Data("ID")
                Set tObj=$classmethod("Sample."_tType,"%OpenId",tVal,,.tSC)  Quit:$$$ISERR(tSC)
                Set tVal=$property(tObj,tSelN)
                Set tSelX = $Case(tSelN, "Home":"Addr", "Office":"Addr", :tSelN)
                Set tVal=$Case(tSelX, "Company":tVal.Name, "Notes":tVal.Read(), "Addr":tVal.Street_", "_tVal.City_" "_tVal.State_" "_tVal.Zip, :tVal)
            } Else {
                Set tVal=tRS.Data(tSelN)
            }
            If "*"=tField {
                Set tObj=$classmethod("Sample."_tType,"%OpenId",tVal,,.tSC)  Quit:$$$ISERR(tSC)
                Set tProxyObj=..buildProxyObj(tObj)
                Do tOut.Write($S(tFirst:"",1:","))
                Set tSC=..ObjectToJSONStream(tProxyObj,.tOut)
            } Else {
                Set:tKeyN'=tSelN tKeyFound=tRS.Data(tKeyN)
                Do tOut.Write($S(tFirst:"",1:",")_"{"_$S(tKeyN=tSelN:"",1:""""_tKeyIn_""":"""_tKeyFound_""", ")_""""_tSel_""":"""_tVal_"""}"_$C(13,10))
            }
            Set tFirst=0
            ZNSpace tNS
            Do tOut.Rewind()  Set tSC1=pOutput.Write(tOut.Read())  Do tOut.Clear()  Set:$$$ISOK(tSC) tSC=tSC1  Quit:$$$ISERR(tSC)
            ZNSpace "SAMPLES"
        } Quit:$$$ISERR(tSC)
        Do:tKeyWild'=tKeyVal pOutput.Write("]"_$C(13,10))
    } catch {
        Kill tRS
        ZNSpace tNS
        Set tSC=$$$SystemError
    }
    Kill tRS
    ZNSpace tNS
    $$$LOGINFO("tSQL: "_tSQL)
    Do:$$$ISOK(tSC) pOutput.SetAttribute("Content-Type","application/json")
    
    while (pOutput.AtEnd = 0){
        set respuestaFinal = pOutput.Read()
    }
    do pOutput.Rewind()
    $$$LOGINFO("respuestaFinal: "_respuestaFinal)
    
    Quit tSC
}

/// Normalize the Person or Employee info by copying its properties to a proxy object in a selective way
ClassMethod buildProxyObj(pObj As %Persistent) [ Internal ]
{
    Set tProxy = ##class(%ZEN.proxyObject).%New()
    Set tProxy.ID=pObj.%Id()
    Set tProxy.Name=pObj.Name
    Set tProxy.Age=pObj.Age
    Set tProxy.DOB=$ZDateTime(pObj.DOB,3)
    Set tProxy.SSN=pObj.SSN
    Set tProxy.FavoriteColors=pObj.FavoriteColors
    Set tProxy.Spouse=pObj.Spouse.Name
    Set tProxy.Home=..buildProxyAddr(pObj.Home)
    Set tProxy.Office=..buildProxyAddr(pObj.Office)
    If pObj.%IsA("Sample.Employee") {
        Set tProxy.Company=pObj.Company.Name
        Set tProxy.Notes=$S($IsObject(pObj.Notes):pObj.Notes.Read(),1:"")
    }
    Quit tProxy
}

ClassMethod buildProxyAddr(pObj As %SerialObject) [ Internal ]
{
    Set tProxy = ##class(%ZEN.proxyObject).%New()
    Set tProxy.Street=pObj.Street
    Set tProxy.City=pObj.City
    Set tProxy.State=pObj.State
    Set tProxy.Zip=pObj.Zip
    Quit tProxy
}

/// Control the type and content of error returned to the REST caller
ClassMethod OnErrorStream(pStatus As %Status)
{
     Set tStream = ##class(%GlobalBinaryStream).%New()  $$$ASSERT($IsObject(tStream))
    Do tStream.Write($ZConvert($$$StatusDisplayString(pStatus)_$C(13,10),"O","UTF8"))
    Set tStream.Attributes("Content-Type")=" text/plain; charset=""UTF-8"""
    Set tStream.Attributes("ResponseCode")="500 Internal Server Error"
     Quit tStream
}

/// Obtener la imagen guardada en TSI 📥📥📥📥
Method consultarImagen(pInput As %Library.AbstractStream, Output pOutput As %Stream.Object) As %Status
{
    Set pOutput=##class(%GlobalBinaryStream).%New()
    set claseAux = ##class(%ZEN.Auxiliary.jsonProvider).%New()
    
    //Convertir el body del JSON a objeto de Ensemble
    set body = pInput.Read()
    $$$LOGINFO("miSCS: body: "_body)
    do pInput.Rewind()
    
    //El mensaje esta en el body
    set tSC= claseAux.%ConvertJSONToObject(.body,"Mensajes.Request.miSCS.ConsultarImagen",.objetoEntrada,1)

    //Enviamos al Proceso
    set tSC = ..SendRequestSync("miSCS",objetoEntrada,.objetoSalida)

    //Convertimos el OBJETO devuelto por el Proceso en JSON
    set tSC = claseAux.%WriteJSONStreamFromObject(.pOutput,.objetoSalida,,,,"aloqtuw")
    
    while (pOutput.AtEnd = 0){
        set respuesta = pOutput.Read()
    }
    do pOutput.Rewind()
    $$$LOGINFO("respuesta: "_respuesta)
    
    $$$LOGINFO("tSC: "_tSC)
    $$$LOGINFO("$$$ISOK(tSC): "_$$$ISOK(tSC))
    
    //Enviamos el JSON con cabeceras
    Do:$$$ISOK(tSC) pOutput.SetAttribute("Content-Type","application/json")

    /*
    do pOutput.SetAttribute("Access-Control-Allow-Origin","*")
    do pOutput.SetAttribute("Access-Control-Allow-Credentials","true")
    do pOutput.SetAttribute("Access-Control-Allow-Methods","GET")
    do pOutput.SetAttribute("Access-Control-Allow-Headers","request,Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers")
    */
    while (pOutput.AtEnd = 0){
        set respuestaFinal = pOutput.Read()
    }
    do pOutput.Rewind()
    $$$LOGINFO("respuestaFinal: "_respuestaFinal)
    Quit tSC
}

}

We are able to use "retrievePerson" succesfully

We send:

http://localhost:19622/aplicaciones/scs/test/miscs/employee/name/Q*/salary

We observe:

With headers:

 

Here comes the challenge:

When we issue:

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

With the following body:

{
    "idApp": "miHistoria",
    "usuario": "11473564",
    "numExpediente": "11473564"
}

It replies nothing:

With the headers:

Besides if we check the trace we see:

 

 

Why we do not see the reply in POSTMAN?

Why headers are "text/html" and not "application/json"?

Could you help us?

 

We have read:

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

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

 

Could you point us to some code, examples or documentation?

 

Thank you for your replies

#Code Snippet #REST API #Ensemble

Source URL:https://community.intersystems.com/post/creating-restful-service-why-custom-method-does-not-return-expected-json