API REST, a una producción, un ejemplo rápido
Bajo el escenario que ya tenemos una API REST, funcionando, y queremos incorporarla a una producción para contar con trazabilidad y todas las ventajas que ofrece IRIS para interoperar, dejo este artículo para cambiar una API existente que responde un JSON, para responder el mismo JSON pero dejando sus trazas en una producción de la misma instancia.
Lo primero, ya contamos con una aplicación creada, llamada /restapi y que tiene como DispatchClass: Testing.REST.ApiDisp (o la clase que tenemos en nuestra instancia).
Este ejemplo, responderá un JSON a la petición: /restapi/test
La clase:
Class Testing.REST.ApiDisp Extends %CSP.REST
{
Parameter HandleCorsRequest = 1;
XData UrlMap [ XMLNamespace = "http://www.widgetsdirect.com/urlmap" ]
{
<Routes>
<Route Url="/test" Method="GET" Call="TestAPI" Cors="false" />
</Routes>
}
ClassMethod TestAPI() As %Status
{
Set %response.ContentType="application/json"
SET retObj = {}
SET retMessage = "API TEST"
SET retEjemplo = "Puede incluir mensajes predeterminados"
SET retObj.Message = retMessage
SET retObj.Ejemplo = retEjemplo
Set retObj.remoteip = %request.CgiEnvs("REMOTE_ADDR")
Set retObj.cluster1 = %request.CgiEnvs("GATEWAY_INTERFACE")
Set retObj.PeerAddr = $SYSTEM.TCPDevice.PeerAddr()
Set retObj.LocalAddr = $SYSTEM.TCPDevice.LocalAddr()
Set person = ##class(Testing.REST.Model.Persons).%OpenId(1)
Set persona = {}
Set persona.nombre = person.Name
Set persona.titulo = person.Title
Set retObj.datos = persona
WRITE retObj.%ToJSON()
QUIT $$$OK
}
}
Es una prueba sencilla en la que además de un mensaje, retrna un objeto persona (usamos el ID 1 sólo como ejemplo).
A la petición GET http://localhost:10012/restapi/test veremos un JSON así en espuesta:
`
{
"Message": "API TEST",
"Ejemplo": "Puede incluir mensajes predeterminados",
"remoteip": "172.26.0.1",
"cluster1": "CGI/1.1",
"cgienvsize": "",
"servername": "localhost",
"PeerAddr": "127.0.0.1",
"LocalAddr": "127.0.0.1",
"datos": {
"nombre": "Campos,Ashley D.",
"titulo": "Assistant Sales Rep."
}
}
`
Vamos a modificar la clase para extender además de %CSP.REST la clase Ens.BusinessService.
Al extender esta clase, podemos agregar en una producción nuestra clase REST (Testing.REST.ApiDisp). Al agregarla, podemos mantener el nombre de la misma clase para instanciar el BS o cambiarle el nombre para hacelo más fácil de identificar. En este caso vamos a usar el nombre REST.BS:
Luego, podemos agregar una línea para crear un BS. La línea que necesitamos:
`Set tSC = ##class(Ens.Director).CreateBusinessService("REST.BS", .Service)`
Vamos a crear un nuevo métod para no perder el que teníamos previamente como referencia solamente. Creamos un método llamado TestAPIBS:
`
ClassMethod TestAPIBS(idperson As %Integer) As %Status
{
Set retObj = {}
Set retMessage = "API TEST"
Set retObj.Message = retMessage
#Dim testreq As Testing.REST.Messages.TestReq
#Dim testresp As Testing.REST.Messages.TestResp
Set testresp = ##class(Testing.REST.Messages.TestResp).%New()
Set testreq = ##class(Testing.REST.Messages.TestReq).%New()
Set tSC = ##class(Ens.Director).CreateBusinessService("REST.BS", .Service)
Set testreq.Codigo = idperson
Set tSC = Service.ProcessInput(testreq,.testresp)
Quit:$SYSTEM.Status.IsError(tSC)
Set %response.ContentType="application/json"
If (testresp.Status = "OK") {
Set persona = {}
Set persona.nombre = testresp.Nombre
Set persona.titulo = testresp.Titulo
Set persona.provincia = testresp.Estado
Set persona.compania = testresp.Company
Set retObj.datos = persona
}Else{
Set retObj.estado = testresp.Status
Set retObj.error = testresp.ErrorDesc
}
Write retObj.%ToJSON()
Quit $$$OK
}
`
Para usar una producción, normalmente se requiere un BP y BO. Para este ejemplo, agregamos una clase tipo Ens.Request y otra tipo Ens.Response para utilizarlas dentro de la producción:
Request:
`
Class Testing.REST.Messages.TestReq Extends Ens.Request
{
Property Codigo As %Integer [ InitialExpression = 1 ];
}`
Response:
`Class Testing.REST.Messages.TestResp Extends Ens.Response
{
Property Codigo As %String(MAXLEN = "");
Property Nombre As %String(MAXLEN = "");
Property Titulo As %String(MAXLEN = "");
Property Estado As %String(MAXLEN = "");
Property Company As %String(MAXLEN = "");
Property Status As %String;
Property ErrorDesc As %String;
}`
A modo de ejemplo, usamos una clase Persona:
`Class Testing.REST.Model.Persons Extends (%Persistent, %Populate, %JSON.Adaptor)
{
Property Name As %String(MAXLEN = "");
Property Company As %String(MAXLEN = "");
Property Title As %String(MAXLEN = "");
Property State As %String(MAXLEN = "");
}`
Trasladamos la lógica de abrir un objeto "Persona" basado en un ID a un BO:
`Class Testing.REST.BO.GetPersonData Extends Ens.BusinessOperation
{
Parameter ADAPTER = "EnsLib.SQL.OutboundAdapter";
Property Adapter As EnsLib.SQL.OutboundAdapter;
Parameter INVOCATION = "Queue";
Method TestConnection(pRequest As Testing.REST.Messages.TestReq, Output pResponse As Testing.REST.Messages.TestResp) As %Status
{
set tSC = $System.Status.OK()
try
{
set pResponse=##class(Testing.REST.Messages.TestResp).%New()
Set person = ##class(Testing.REST.Model.Persons).%OpenId(pRequest.Codigo)
If $ISOBJECT(person) {
Set pResponse.Status = "OK"
Set pResponse.Codigo = person.%Id()
Set pResponse.Nombre = person.Name
Set pResponse.Titulo = person.Title
Set pResponse.Company = person.Company
Set pResponse.Estado = person.State
}
else {
Set pResponse.Status = "NOK"
Set pResponse.ErrorDesc = "No se encuentra persona " _ pRequest.Codigo
}
}
catch (tException)
{
set tSC = tException.AsStatus()
set pResponse.ErrorDesc = $System.Status.GetErrorText(tSC)
}
quit tSC
}
XData MessageMap
{
<MapItems>
<MapItem MessageType="Testing.REST.Messages.TestReq">
<Method>TestConnection</Method>
</MapItem>
</MapItems>
}
}
`
Un BP que conectará nuestro BS con el BO:
Ahora modificamos la clase Dispatch para manejar las llamadas al GET que use el método creado (TestAPIBS):
`<Route Url="/testbs/:id" Method="GET" Call="TestAPIBS" Cors="false" />`
Agregamos el parámetro "id" sólo para hacer interactivo el GET y poder obtener la información de la persona basados precisamente en este Id.
Para el GET http://localhost:10012/restapi/testbs/10
Podemos ver una respuesta como esta:
Espero esto ayude a quienes inician con creación de APIs con IRIS, y puedan agregar funcionalides.