#Ensemble

0 Seguidores · 196 Publicaciones

InterSystems Ensemble es una plataforma de integración completa y fácil de utilizar la cual permite que los usuarios se conecten con personas, procesos y aplicaciones en un tiempo

récord.

Aprende más

Documentación

Artículo Kurro Lopez · ago 31, 2021 2m read

Como sabes, ObjectScript no tiene un comando o función de sistema FOREACH.
Pero tiene un amplio margen para la creatividad.

Pero la tarea es recorrer una matriz global o local y hacer algo PARA CADA elemento.

Hay dos posibles soluciones:

  • Crear una macro que genere las secuencias de código requeridas
  • Crear un comando extendido para realizar la acción.
0
0 171
Pregunta Laura Blázquez García · ago 20, 2021

Tengo una clase que parsea un XML para extraer toda la información. En este XML hay un atributo que tiene saltos de línea:

<record date="2021-08-11T14:25:21" entity="TEXTO"><OBSERVACIONES o="" n="Esto es un texto de prueba:
1. Contiene información importante
2. Es útil para el usuario
3. Sigue siendo una prueba"/></record>

Usando %XML.TextReader puedo acceder a toda la información del XML, pero esos saltos de línea se pierden. Esto es lo que obtengo:

2
0 878
Artículo Eduardo Anglada · ago 12, 2021 3m read
Este es un ejemplo de código que funciona en IRIS 2020.1 y en Caché 2018.1.3 
No se mantendrá sincronizado con las nuevas versiones.      
Y NO cuenta con el servicio de soporte de InterSystems.

En la mayoría de los casos, un global que se utiliza como almacenamiento predeterminado tiene solo 1 nivel de subíndice que representa el IDKEY.
Para un índice de globals podemos ver 2 o más niveles de subíndices.
Las matrices, las relaciones de herencia padre hijo o las clases persistentes que extienden una clase base, son ejemplos en los que vemos más niveles. Aunque todos estos globals son bastante uniformes.

Y después vemos globals que no están relacionados con clases o tablas como ^SPOOL,  ^ERRORS, o ^%SYS, en los que la estructura depende de varios niveles de subíndices con un significado especial.

El análisis de esos globals no convencionales es un reto y el simple hecho de descargarlos no necesariamente ayuda a comprender las dependencias.

Este ejemplo está orientado al viejo chiste:  "¿Cómo se come un elefante?" ==> "¡Cortándolo en porciones!"

Esa es la oferta:
Por medio de una sentencia SQL, se puede mostrar la estructura de cualquier global por niveles.
Tú proporcionas el nombre del global y el nivel máximo que mostrará, y obtienes los subíndices relacionados, $Data del nodo, la cantidad de los siguientes subnodos y, si está disponible, el contenido almacenado en ese nivel.

Por ejemplo: SELECT * FROM rcc_G.scan where rcc_G.Scan('^%SYS',1)=1

Reference       Level $D SubN  Value
^%SYS               0   10 25    
("CSP")             1   10       
("CSPAppSec")       1   1       64
("CacheTempDir")    1   1      "c:\intersystems\iris\mgr\iristemp\"
("DBRefByName")     1   10       
("Ensemble")        1   11     "2020-04-25 18:37:18"
("ErrorPurge")      1   1      30
("FIPSMode")        1   1      0
("IRISTempDir")     1   1      "c:\intersystems\iris\mgr\iristemp\"
("JOURNAL")         1   11     0
("LANGUAGE")        1   10       
("LASTSESSIONGUID") 1   1     "EÊcRù¢GM£ô"_$c(127)_"¹9¾ÒÆ"
("LOCALE")          1   10       
("ModuleRoot")      1   10       
("NLS")             1   10       
("SERVICE")         1   10       
("SSPort")          1   1     51773
("StreamLocation")  1   10       
("SystemMode")      1   1     "TEST"
("TempDir")         1   1     "C:\InterSystems\IRIS\mgr\Temp"
("WebServer")       1   10       
("bindir")          1   1     "c:\intersystems\iris\bin\"
("shutdownlogerrors") 1 1 0
("sql")             1   10       
("sysdir")          1   1     "c:\intersystems\iris\mgr\"
("tercap")          1   10       
26 lines

SELECT * FROM rcc_G.scan where rcc_G.Scan('^%SYS',2)=1

Reference                   Level $D SubN   Value
^%SYS                           0   10 25  
("CSP")                         1   10 1  
("CSP","LastUpdate")            2   1        "65553,44452"
("CSPAppSec")                   1   1  0     64
("CacheTempDir")                1   1  0     "c:\intersystems\iris\mgr\iristemp\"
("DBRefByName")                 1   10 9     
("DBRefByName","CACHE")         2   1        "^^c:\intersystems\iris\mgr\cache\"
("DBRefByName","CACHEUSER")     2   1        "^^c:\intersystems\user\"
("DBRefByName","ENSLIB")        2   1        "^^c:\intersystems\iris\mgr\enslib\"
("DBRefByName","IRISAUDIT")     2   1        "^^c:\intersystems\iris\mgr\irisaudit\"
("DBRefByName","IRISLIB")       2   1        "^^c:\intersystems\iris\mgr\irislib\"
("DBRefByName","IRISLOCALDATA") 2   1        "^^c:\intersystems\iris\mgr\irislocaldata\"
   &lt; 60 lines more >

SELECT * FROM rcc_G.scan where rcc_G.Scan('^ERRORS',37)=1 and id['Jour'

Reference                                            Level    $D  SubNodes    Value
(65588,1,"*STACK",1,"V","%00000","N","""JournalState""")    8   1    0         4
(65592,1,"*STACK",1,"V","%00000","N","""JournalState""")    8   1    0         4
(65592,2,"*STACK",1,"V","%00000","N","""JournalState""")    8   1    0         4
0
0 175
Artículo Ricardo Paiva · jul 29, 2021 2m read

En SQL, la condición más frecuente WHERE se relaciona principalmente con el contenido de las filas en las que trabajas.
Por lo tanto, debe calcularse y verificarse para cada fila a la que accedas.
Distinto es el caso (y por eso la llamé ESTÁTICA) de una condición WHERE independiente de las filas a las que accedes.

0
0 178
Artículo Ricardo Paiva · jul 22, 2021 3m read

Posiblemente te hayas encontrado con esto y no supiste cómo evitarlo; o tal vez ni siquiera te diste cuenta...

Pero cuando se tienen componentes empresariales de la Producción de Interoperabilidad TCP (por ejemplo, un business service HL7), probablemente tienes (dependiendo de tu configuración de StayConnected) muchas entradas en el Registro de Eventos (Event log) de tipo Info. Cada entrada registraría una conexión o desconexión.

Por ejemplo:

0
0 156
Artículo Ricardo Paiva · jul 1, 2021 3m read

¡Hola a todos!

InterSystems IRIS tiene un menú llamado Interoperabilidad.

Ofrece mecanismos que permiten crear fácilmente integraciones de sistemas (adaptadores, mapas de registros, BPMs, conversiones de datos, etc.), para que diferentes sistemas puedan conectarse fácilmente.

En el proceso de transmisión de datos se pueden incluir diversas operaciones, por ejemplo: para conectar sistemas que normalmente no están conectados, se pueden recibir (o enviar) datos según las especificaciones del sistema de destino. Además, se puede adquirir y añadir información desde otro sistema antes de enviar los datos. La información también se puede adquirir y actualizar a partir de una base de datos (IRIS u otra).

En esta serie de artículos, comentaremos los siguientes temas, mientras vemos ejemplos de códigos para ayudarte a comprender cómo funciona y qué tipo de desarrollo se requiere cuando se integran sistemas con Interoperabilidad.

En primer lugar, os presento el caso de estudio que utilizaremos en esta serie de artículos:

Una empresa gestiona una tienda online y está cambiando el orden en que se muestra la información de los productos para que coincida con las estaciones del año.
Sin embargo, algunos artículos se venden bien independientemente de la estación del año, mientras otros se venden en momentos inesperados, lo que no coincide con la regla actual de cambiar el orden.
Por lo tanto, estudiamos la posibilidad de cambiar el orden para que coincida con la temperatura del día en lugar de con la estación del año. Fue necesario saber la temperatura de los productos comprados en ese momento.
Como se dispone de una API web externa para comprobar la información meteorológica, planeamos recopilar la información meteorológica en el momento de la compra y registrarla en la base de datos.

Es muy sencillo, pero es necesario utilizar una “API web externa” para recoger la información, y se debe combinar la información obtenida y la de compra para registrarla en la base de datos.

Las instrucciones específicas se comentarán en un artículo relacionado (no incluye la creación de un sitio web). ¡Échale un vistazo!

En cuanto a la "API web externa" que estamos utilizando en esta ocasión, estamos usando los Datos meteorológicos actuales de OpenWeather.

(Si quieres probarlo, debes registrar una cuenta y obtener un ID de API ).

Lo siguiente es el resultado de una solicitud GET de un cliente REST (lo ejecutaremos en el mecanismo que implementaremos en Interoperabilidad).

El JSON de la respuesta HTTP es el siguiente:

{
    "coord": {
        "lon": 135.5022,
        "lat": 34.6937
    },
    "weather": [
        {
            "id": 803,
            "main": "Clouds",
            "description": "broken clouds",
            "icon": "04d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 17.05,
        "feels_like": 13.33,
        "temp_min": 16,
        "temp_max": 18,
        "pressure": 1017,
        "humidity": 55
    },
    "visibility": 10000,
    "wind": {
        "speed": 4.63,
        "deg": 70
    },
    "clouds": {
        "all": 75
    },
    "dt": 1611635756,
    "sys": {
        "type": 1,
        "id": 8032,
        "country": "JP",
        "sunrise": 1611612020,
        "sunset": 1611649221
    },
    "timezone": 32400,
    "id": 1853909,
    "name": "Osaka",
    "cod": 200
}

En el siguiente artículo, comentaremos cómo funciona el menú de Interoperabilidad para la integración del sistema.

0
0 233
Pregunta Yone Moreno · jun 30, 2021

Hola, buenos días.

Necesitaríamos orientación, guía o apoyo de ustedes para realizar lo siguiente:

Nuestro objetivo es: lograr que el fichero ".stream" NO se guarde, en la carpeta: /opt/ensemble/[Entorno]/stream

Tenemos un Servicio REST, un Proceso y una Operacion REST

Desde la Operacion al Proceso existe un Mensaje Response: Mensajes.Response.HistoriaClinica.GetInformeResponse

con un pdf definido como:

Property pdf As %GlobalCharacterStream;

Además, desde el Proceso al Servicio nuestro Mensaje Response es: Mensajes.Response.Informes.v02r00.obtenerCartillaVerdeDigitalResponse

1
0 255
InterSystems Official Mario Sanchez Macias · jun 18, 2021

De vez en cuando, InterSystems discontinúa el desarrollo de una tecnología, cuando hay disponibles otras opciones mejores y más modernas. Sin embargo, el soporte a esas funcionalidades continúa de la misma forma que los productos fuera de la Versión Minima Soportada.

0
0 190
Artículo Alberto Fuentes · jun 15, 2021 2m read

¿Os gustaría poder acceder al Terminal Web directamente desde vuestro VSCode?

Este es otro genial artículo de la serie de Tani Frankel sobre "Trucos y consejos de VSCode" y es bastante similar al anterior sobre el Asistente SOAP.

Es el mismo principio y se obtiene el mismo resultado, aunque el caso de uso es diferente.

Supongamos que quieres abrir desde VSCode el WebTerminal (para quienes aún no están familiarizados con esta excelente herramienta diseñada por el increíble @Nikita Savchenko, consulten la web del proyecto).

Puedes adoptar un enfoque similar al del artículo anterior. Describimos nuevamente cuáles son los pasos:

  • En la configuración (settings) de JSON, abre la extensión de ObjectScript
  • En el objeto "conn", añade un objeto "links"
  • Dentro de "links" añade esta línea:
            "$(terminal) WebTerminal": "${serverUrl}/terminal/?ns=${ns}${serverAuth}"

Esto se verá así:

 

Una vez hecho esto, cuando hagas clic en la opción Connection en la parte inferior de la barra de estado de VSCode, deberías encontrar el Terminal web en el menú.

Esto se mencionó en este debate sobre Problemas con VSCode que se encuentra en el GitHub VSCode ObjectScript (acerca de las variables ${...} que se utilizaron en la URL anterior), con comentarios de @John Murray 

Os dejo un breve GIF mostrando el proceso (comienza con el menú estándar y termina con la opción de lanzar el Terminal web).

 

0
1 288
Artículo Alberto Fuentes · jun 8, 2021 3m read

Otro artículo sobre "Trucos y consejos de VSCode" -

¿Quieres ver esta opción en VSCode?

Esta vez nos centraremos en cómo obtener el Asistente SOAP (*SOAP Wizard*) tal y como estaba disponible en Studio — para definir un cliente de servicio web SOAP basado en WSDL (y *Business Operation*), o servicio —.

Si trabajas con Servicios web (Web services), lo más probable es que hayas utilizado el Asistente SOAP en Studio. Lo abrirías en Tools > Add-Ins:

Y este abría una "Server Template":

En VSCode, puede que te preguntes cómo puedes acceder a eso.

Bueno, el hecho básico que hay que comprender es que realmente este complemento o asistente es simplemente una página web, que se muestra en Studio como hemos visto anteriormente y, como tal, también se puede acceder a ella desde un simple navegador. VSCode facilita la apertura de dicho navegador con el contenido deseado (construyendo la URL correcta con el nombre del servidor, el puerto, la aplicación web, etc.).

El resultado sería el mismo que ver una opción para abrir el Portal de administración o la Referencia de clase (con las URLs correspondientes) al hacer clic en la Conexión del servidor sobre la barra de estado inferior de VSCode, por ejemplo:

También verás una entrada para el Asistente SOAP.

Puedes conseguir esto al añadir una entrada 'links' a tu objeto 'conn' que se encuentra en tu configuración de JSON de tu extensión ObjectScript, y especificando la URL deseada (utilizando las variables correspondientes).

Esto se mencionó en un debate sobre Problemas con VSCode que se encuentra en el GitHub VSCode ObjectScript, como problema "Asistente SOAP", con comentarios de @John Murray y @Ondřej Hoferek, y también se menciona en esta respuesta de @Timothy Leavitt a una pregunta de la Comunidad.
 

El valor JSON sería:

"SOAP Wizard": "${serverUrl}/isc/studio/templates/%25ZEN.Template.AddInWizard.SOAPWizard.cls?Namespace=${namespace}${serverAuth}"

Y esta parte se vería así:

Una vez que tengas esto, verás una opción adicional cuando hagas clic en la Conexión -

Y al elegir esa opción accederás al esperado asistente (abierto en un navegador):

Os dejo un breve GIF mostrando este proceso (comienza por el menú normal al hacer clic en la Conexión, y termina con el menú que incluye el Asistente SOAP).

 

Fíjate que hay otros asistentes (o plantillas) que puedes añadir de esta manera (como el Asistente XSD, por ejemplo).

2
1 1128
Artículo Eduardo Anglada · jun 9, 2021 3m read
Este es un ejemplo de código que funciona en IRIS 2020.1 y en Caché 2018.1.3 
No se mantendrá sincronizado con las nuevas versiones      
¡NO está soportado por el servicio de soporte de InterSystems!   

Los globals en Caché, Ensemble e IRIS normalmente son invisibles a través de SQL. En este ejemplo se muestra cómo verlos desde SQL. Los globals se muestran como el contenido de una tabla con sus subíndices y su contenido almacenado.
El global que se quiere mostrar se pasa a SQL por medio de una condición estática WHERE que requiere de 3 parámetros:

  • el nombre del global (obligatorio)
  • el subíndice de inicio (opcional)
  • el subíndice de parada (opcional)

Solo con proporcionar el nombre del global se obtiene todo su contenido. Los globals también se pueden obtener usando la referencia extendida y, como se trata de una tabla SQL, se pueden aplicar todas las condiciones adicionales que queramos.

Ten cuidado: Poner correctamente las comillas entre SQL y Caché/Ensemble/IRIS puede ser todo un desafío.

Por ejemplo:
select * from zrcc_G.dump where zrcc_G.Dump('^|"CACHE"|Sample.PersonD',2,4)=1

ID         Global           Subscript         Value
1   ^|"CACHE"|Sample.PersonD    (2) $lb("",792533244,"GlobaDynamics Holdings Inc.",64256,"C1787","Y5365","A5","A658","R1770","","Ironhorse,Alice D.","T3710","O3","I4011","W8367","557-37-6758",83059958205089661,"1841-01-02 00:00:00")
2   ^|"CACHE"|Sample.PersonD    (3) $lb("",862705606,"TeleLateral Associates",34553,"V8155","T8918","X9","V8732","K1167","","Eisenstien,Peter E.","H208","C8","Q2015","Q3357","702-46-8467",57275722714358892,"2020-06-23 13:27:18")
3   ^|"CACHE"|Sample.PersonD    (4) $lb("",677194559,"RoboSoft Group Ltd.",52738,"F4851","Z364","S8","O6888","O4367","","Eagleman,Clint C.","C8051","R6","V1659","C9814","664-33-8809",-53705244349891319,"2020-06-23 13:27:18")

select TOP 15 * from zrcc_G.dump where zrcc_G.Dump('^%SYS','"JOURNAL"')=1

ID  Global         Subscript             Value
1   ^%SYS   ("JOURNAL")            0
2   ^%SYS   ("JOURNAL","ALTDIR")   "C:\InterSystems\IRIS\altjournal\"
3   ^%SYS   ("JOURNAL","CURDIR")   "C:\InterSystems\IRIS\mgr\journal\"
4   ^%SYS   ("JOURNAL","CURRENT")  "1^C:\InterSystems\IRIS\mgr\journal\20200801.009"
5   ^%SYS   ("JOURNAL","EXPSIZE")  0
6   ^%SYS   ("JOURNAL","LAST")     "1^C:\InterSystems\IRIS\mgr\journal\20200801.009"
7   ^%SYS   ("JOURNAL","LIFESPAN","FILE")   "2,2"
8   ^%SYS   ("JOURNAL","MAXSIZE")    1073741824
9   ^%SYS   ("JOURNAL","PREFIX")   ""
10  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.001")    "2019-11-07 17:38:30"
11  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.002")    "2019-11-07 17:38:30"
12  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.003")    "2019-11-07 17:38:30"
13  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.004")    "2019-11-07 17:38:30"
14  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.005")    "2019-11-08 08:39:47"
15  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191105.001")    "2019-11-08 08:39:47"
0
0 159
Artículo Alberto Fuentes · jun 1, 2021 4m read

¡Hola Comunidad!

¿Necesitas conectar tu VSCode a un servidor de InterSystems? Le echamos un vistazo hoy a un gran truco que nos pasa Tani Frankel

¿Has oído hablar de esta opción?

Con cada vez más personas usando VSCode como IDE para nuestros productos, pensé que podría ser beneficioso ir ofreciendo pequeños trucos y consejos para ayudar a la gente a empezar a utilizarlo y a ser más productiva. Así que, con esta publicación, comienzo la serie de pequeños artículos.

Unas aclaraciones importantes:

  1. Esto no pretende ser un tutorial ni un método de aprendizaje formal - si buscas uno de ellos, puedes echar un vistazo a este excelente ejercicio online o revisar esta estupenda sesión de nuestro último Virtual Summit. 

  2. Estos "Trucos y consejos" no son de mi invención - normalmente ya están documentados o se mencionan en algún lugar, yo solo quería reunirlos y quizá ofrecer un poco más de orientación o ejemplos. Trataré de referirme a la fuente cuando sea importante.

  3. Aunque ya he anotado algunas ideas y temas que quiero cubrir en esta "serie", no sé cómo de rápido voy a ser capaz de publicarlas, así que no puedo comprometerme con la frecuencia con la que aparecerán...

Aquí va el primero de los "trucos y consejos":

Una de las primeras cosas que tendrás que hacer en VSCode es definir tus conexiones al servidor. Puedes hacerlo manualmente dentro del archivo de Configuración (Settings) de JSON en la extensión InterSystems Server Manager, o pulsando el signo (+) mientras intentas conectarte a un servidor (y respondes a las indicaciones), pero si estás en Windows, simplemente puedes importar tus definiciones del servidor desde el Registro de Windows.

De hecho, esto está documentado como parte de la documentación de la extensión InterSystems Server Manager - en el Marketplace de extensiones de VSCode, en el archivo Readme del Repositorio GitHub, y como se muestra en la página de Detalles de la extensión dentro del propio VSCode, realmente todo el mismo texto...) -

En Windows, puedes ejecutar Import Servers from Registry desde Command Palette para crear entradas de conexión para todas las conexiones que hayas definido previamente con InterSystems Server Manager.

  Cuando instalas una instancia en un equipo con Windows, o defines servidores para un cliente por medio de la herramienta Server Manager, se actualiza el Registro de Windows.

Por ejemplo, tenía un cliente con 9 servidores diferentes, a los que podría querer conectarse (entornos de Producción / Desarrollo / Pruebas, LAN vs. DMZ, etc.); otro cliente tiene incluso más (muchos más). Hacer esto uno por uno en VSCode podría ser tedioso (y propenso a errores humanos). 

Supongamos que, por ejemplo, tengo esta situación en mi equipo, como se define en InterSystems Server Manager -

Puedo utilizar la opción "Import Servers From Registry" en la extensión InterSystems Server Manager.

Simplemente abre Command Palette (View -> Command Palette... o Ctrl+Mayúscula+P), empieza a escribir "InterSystems" después del carácter > y deberías ver esta opción -

Otra opción que puedes utilizar es hacer click en los ... (3 puntos) en la esquina superior derecha del panel de InterSystems Tools, y te aparecerá la opción:

A continuación, se te pedirá un nombre de usuario (Username) para conectarse a uno de los servidores (no tienes que introducir uno si no quieres que se guarde, sino que se te pedirá cada vez que te conectes), luego una contraseña, si quieres guardar la contraseña para todos los demás servidores también (no tienes que guardar la contraseña en absoluto si no quieres) y entonces se añadirán todas las definiciones del servidor.

Por ejemplo, según la imagen del Server Manager de arriba (y asumiendo que proporcioné un nombre de usuario de SuperUser, así es como se verá la configuración de JSON después de la importación -

Aquí os dejo un breve GIF mostrando este rápido proceso (comienza con solo tener definidas las 3 conexiones predeterminadas del servidor, y termina con los 5 servidores adicionales según el ejemplo anterior):

 

0
0 168
Artículo Alberto Fuentes · mayo 19, 2021 1m read

En Studio, podías abrir una clase directamente usando su nombre, sin tener que recorrer completamente el árbol de paquetes con un montón de clics hasta llegar a la clase deseada.

Con Ctrl + O o (File -> Open) podías escribir el nombre de la clase de forma sencilla, por ejemplo:

Pulsabas Enter y voilà!, la clase se abría.

¿Cómo se logra esto en VSCode?

En realidad es bastante sencillo, con Ctrl + T (por ejemplo, en Windows), o Go -> Go to Symbol en el espacio de trabajo..., escribes el nombre de la clase... ¡y listo!

Por ejemplo:

Esta solución fue mencionada por @Dmitry Maslennikov como una sugerencia para un informe de incidencias en GitHub (marcada como enhacement request, mejora del productopara este tipo de funciones - "Abrir la clase por su nombre desde el servidor".

Este es un breve GIF para demostrar cómo funciona:

 

0
0 974
Pregunta Dani Fibla · abr 27, 2021

Tengo una duda referente al Visual Studio Code,  el Studio del Iris permite hacer debug de cualquier business operation/proces que este en la producción añadiendo el proceso que se le haya asignado dentro de las opciones Debug(Attach), al reenviar un mensaje que entre dentro de esta operación/proceso se parará en nuestro punto de interrupción.

¿Como puedo conseguir esto con el Visual Studio Code?

He revisado varios pluggins para hacer debug pero he sido incapaz de conseguirlo.

4
0 333
Pregunta Oscar Muñoz · abr 14, 2021

Hola a todos, 

Estoy creando un WS como servidor, pero a la hora de pedir el WSDL me está dando un error porque no encuentra la clase.
He añadido las siguientes intrucciones:

set ^SYS("Security","CSP","AllowClass","MiProyecto.MiClaseWS","%SOAP.WebServiceInfo")=1 
set ^SYS("Security","CSP","AllowClass","MiProyecto.MiClaseWS","%SOAP.WebServiceInvoke")=1

He creado una entrada en la configuracion de seguridad del WS

En la solapa de Application Role he puesto los permisos de %All 

(He puesto el Namespaces "Samples" en la imagen por motivos de seguridad)

2
0 351
Artículo Alberto Fuentes · abr 7, 2021 6m read

Hola a todos! Os traigo hoy un ejemplo de código que compartía Robert Cemper para mostrar por SQL los registros de error almacenados en ^ERRORS.

Este es un ejemplo de código que funciona en Caché 2018.1.3 e IRIS 2020.2 
No se mantendrá sincronizado con las nuevas versiones. 
Es un ejemplo de código y como tal no está soportado por el Soporte de InterSystems

Los errores en IRIS/Caché/Ensemble se registran entre otros en la global ^ERRORS. Como este mecanismo se remonta a muchas versiones atrás (décadas del milenio anterior!) su estructura está lejos de las estructuras de almacenamiento de SQL típicas.

El global se escribe mediante la rutina ^%ETN.int y el contenido se hace visible desde la línea de comandos del terminal mediante la rutina ^%ERN o en el Portal de Administración como Log de Errores de la Aplicación.

Por defecto no está disponible a través de SQL ya que no hay ninguna clase que lo presente como tabla. Por varias razones:

  • Cuando se diseñó, era una buena práctica tener estructuras similares a índices en los mismos globals que los datos. Si digo "similares", significa que no sirve para SQL.
  • El contenido de los objetos va a niveles más profundos que el resto. En consecuencia, la profundidad de los subíndices (normalmente IdKey) varía de 3 a 11.

^ERRORS es independiente en cada namespace. Está estructurado por Day, SequenceByDay, Type, ItemName (Variable, OREF),Value.

zrcc.ERRORStack muestra esta información como tabla SQL.
El contenido más profundo de los objetos se hace visible por la consulta personalizada incluida.
El procedimiento SQL zrcc.ERRORStack_Dump(Day,Sequence) devuelve todo el contenido disponible y presenta subíndices y valores como se ve en la lista de globals.

A continuación veremos cómo sacar partido de estas utilidades:

Primero: localiza el día que te interese y el número de secuencia con la ayuda de SQL

Por ejemplo: SELECT * FROM zrcc.ERRORStack where item='$ZE'

        Day  Seq    Stk Type    Item    Value
    2020-07-02  1    0     V      $ZE   &lt;WRITE>zSend+204^%Net.HttpRequest.1
    2020-07-07  1    0     V      $ZE   &lt;WRITE>zSend+204^%Net.HttpRequest.1
    2020-07-15  1    0     V      $ZE   &lt;WRITE>zSend+204^%Net.HttpRequest.1
    2020-07-20  1    0     V      $ZE   &lt;LOG ENTRY>
    2020-07-26  1    0     V      $ZE   &lt;WRITE>zSend+204^%Net.HttpRequest.1

A continuación, llama al procedimiento en SQL:   CALL zrcc.ERRORStack_Dump('2020-07-26',1)

Row count: 541 Performance: 0.026 seconds  6557 global references
Ref                                 Value
2020-07-26,1,"*STACK",0,"V","Routine")  zSend+204^%Net.HttpRequest.1
2020-07-26,1,"*STACK",1,"I")    1^S^^^0^
2020-07-26,1,"*STACK",1,"L")    1 SIGN ON
2020-07-26,1,"*STACK",1,"S")    
2020-07-26,1,"*STACK",1,"T")    SIGN ON
2020-07-26,1,"*STACK",1,"V","%dsTrackingKeys","N","""Analyzer""")   6
2020-07-26,1,"*STACK",1,"V","%dsTrackingKeys","N","""Architect""")  7
2020-07-26,1,"*STACK",1,"V","%dsTrackingKeys","N","""DashboardViewer""")    8
2020-07-26,1,"*STACK",1,"V","%dsTrackingKeys","N","""ResultSet""")  9
2020-07-26,1,"*STACK",1,"V","%objcn")   2
2020-07-26,1,"*STACK",3,"V","Task") &lt;OBJECT REFERENCE>[1@%SYS.Task]
2020-07-26,1,"*STACK",3,"V","Task","OREF",1)    142
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,0)  3671
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,1)  +----------------- general information ---------------
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,2)  | oref value: 1
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,3)  | class name: %SYS.Task
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,4)  | %%OID: $lb("13","%SYS.Task")
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,5)  | reference count: 5
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,6)  +----------------- attribute values ------------------
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,7)  | %Concurrency =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,8)  4 &lt;Set>
- - - 
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,53) | EmailOutput =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,54) 0
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,55) | EndDate =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,56) ""
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,57) | Error =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,58) "&lt;WRITE>zSend+204^%Net.HttpRequest.1"
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,59) | Expires =
- - -
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,111)    | Status =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,112)    "0 "_$lb($lb(5002,"POST to Server Failed",,,,,,,,$lb(,"%SYS",$lb("$^zSend+204^%Net.HttpRequest.1 +1","$^zPost+1^%Net.HttpRequest.1 +1","$^zSendData+20^FT.Collector.1 +1","$^zTransfer+12^FT.Collector.1 +1","$^zOnTask+3^%SYS.Task.FeatureTracker.1 +1","D^zRunTask+74^%SYS.TaskSuper.1 +1","$^zRunTask+54^%SYS.TaskSuper.1 +1","D^zRun+26^%SYS.TaskSuper.1 +1"))),$lb(6085,"ISC.FeatureTracker.SSL.Config","SSL/TLS error in SSL_connect(), SSL_ERROR_SSL: protocol error, error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed",,,,,,,$lb(,"%SYS",$lb("e^zSend+303^%Net.HttpRequest.1^1","e^zPost+1^%Net.HttpRequest.1^1","e^zSendData+20^FT.Collector.1^1","e^zTransfer+12^FT.Collector.1^1","e^zOnTask+3^%SYS.Task.FeatureTracker.1^1","e^zRunTask+74^%SYS.TaskSuper.1^1","d^zRunTask+54^%SYS.TaskSuper.1^1","e^zRun+26^%SYS.TaskSuper.1^1","d^^^0"))))/* ERROR #5002: Cache error: POST to Server Failed- ERROR #6085: Unable to write to socket with SSL/TLS configuration 'ISC.FeatureTracker.SSL.Config', error reported 'SSL/TLS error in SSL_connect(), SSL_ERROR_SSL: protocol error, error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed' */
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,113)    | SuspendOnError =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,114)    0
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,115)    | Suspended =
- - -
2020-07-26,1,"*STACK",6,"V","Status1")  1
2020-07-26,1,"*STACK",6,"V","Task") &lt;OBJECT REFERENCE>[1@%SYS.Task]
2020-07-26,1,"*STACK",6,"V","Task","OREF",1)    142
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,0)  3671
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,1)  +----------------- general information ---------------
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,2)  | oref value: 1
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,3)  | class name: %SYS.Task
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,4)  | %%OID: $lb("13","%SYS.Task")
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,5)  | reference count: 5
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,6)  +----------------- attribute values ------------------
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,7)  | %Concurrency =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,8)  4 &lt;Set>
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,9)  | DailyEndTime =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,10) 0
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,11) | DailyFrequency =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,12) 0
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,13) | DailyFrequencyTime =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,14) ""
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,15) | DailyIncrement =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,16) ""
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,17) | DailyStartTime =
- - - 
2020-07-26,1,"*STACK",12,"V","%00000","N","""JournalState""")   12
2020-07-26,1,"*STACK",13,"I")   13^Z^ETNERRB^%ETN^0
2020-07-26,1,"*STACK",13,"L")   13 ERROR TRAP S $ZTRAP="ETNERRB^%ETN"
2020-07-26,1,"*STACK",13,"S")   S $ZTRAP="ETNERRB^%ETN"
2020-07-26,1,"*STACK",13,"T")   ERROR TRAP

541 row(s) affected
0
0 200
InterSystems Official Mario Sanchez Macias · mar 30, 2021

InterSystems ha corregido un defecto que puede ocasionar problemas de inconsistencia de datos en miembros de mirror no-primarios en circunstancias excepcionales. Este defecto afecta a todas las versiones de los productos de InterSystems.

0
0 116
Artículo Bernardo Linarez · oct 28, 2020 12m read

Prometheus es uno de los sistemas de monitorización adaptado para recoger datos de series temporales.

Su instalación y configuración inicial son relativamente sencillos. El sistema tiene un subsistema gráfico integrado llamado PromDash para la visualización de datos, pero los desarrolladores recomiendan usar un producto de otro proveedor, llamado Grafana. Prometheus puede monitorizar muchas cosas (hardware, contenedores, distintos sistemas de gestión de base de datos), pero en este artículo me gustaría analizar la monitorización de una instancia de Caché (para ser exactos, será una instancia de Ensemble, pero las métricas serán de Caché). Si te interesa, sigue leyendo.

1
0 457
Artículo Eduardo Anglada · ene 22, 2021 3m read

Actualización: se añadió soporte para el modelo de regresión ¡Hola a todos!

En este breve artículo, os mostraré cómo escribir un adaptador para utilizar la interoperabilidad de IRIS con los modelos de Machine Learning (ML) administrados por IntegratedML de IRIS.

El adaptador

El adaptador solo utiliza las funciones SQL PREDICT y PROBABILITY de IntegratedML. Es solo una sencilla consulta SQL:
code1
Tened en cuenta que el nombre del modelo se obtiene a partir de la propiedad denominada "Model". Dicha propiedad debe estar definida en la clase host que utiliza el adaptador, de lo contrario se producirá una excepción. Por ejemplo:


La lista de los modelos en la configuración del adaptador se realiza en dos pasos:
  1. Creación de un método en una clase que sea hija de %ZEN.Portal.ContextSearch para tener todos los modelos de clasificación y que los devuelva (dc.Ens.Adapter.ClassficationMLContextSearch)
    code2
  2. Configuración de dicha clase y método como un alimentador para la propiedad Model que se encuentra en el parámetro SETTINGS en la clase del adaptador (dc.Ens.Adapter.ClassificationMLAdapter)
    code3
    Para los modelos de regresión, existe la clase dc.Ens.Adapter.RegressionMLContextSearch, que carga todos los modelos de regresión.

En este caso, el filtro MODE_TYPE se configuró como 'regression' en vez de 'classfication':

### Cómo utilizar el adaptador

Para la demostración, simulé un sencillo sistema de pago para las transacciones con tarjeta de crédito, con capacidad de detectar fraudes mediante un modelo de clasificación con ML. Cuando detecta una transacción sospechosa, emite una alerta.

Para utilizar el adaptador, cread una clase host (una clase Business Process o Business Operation) que utiliza como adaptador la clase dc.ENS.Adapter.ClassificationMLAdapter.
code4
Ahora, podéis utilizar el método del adaptador Classify(), y proporcionar una muestra de las características esperadas por el modelo:
Para utilizarlo, cread una clase host (una clase Business Process o Business Operation) que utilice como adaptador la clase dc.ENS.Adapter.ClassificationMLAdapter
code5
Podéis usarlos según vuestras necesidades. En el ejemplo, solo era necesario el resultado para la predicción de fraudes, por lo que la clase Business Operation solo utiliza el valor devuelto en la propiedad Predicted:
code6
Para los modelos de regresión, los resultados se modelan mediante la clase dc.Ens.Adapter.RegressionResult. Esta clase tiene una propiedad llamada Estimated.

Para obtener un valor estimado a partir de una muestra, la clase adaptador para el modelo de regresión tiene el método Estimate.

El resultado final se muestra a continuación:
code7
El código completo está disponible en OpenExchange. Espero que os resulte útil. José

0
0 149
Artículo Dani Fibla · dic 5, 2020 7m read

Cuando se llama a los servicios web, existen varios escenarios para los Business Operation, que actúan juntos para controlar lo que sucederá cuando no se obtenga una respuesta en el tiempo deseado. (Esto también es importante, por ejemplo, en el caso de una solicitud HTTP simple que no pertenezca a los servicios SOAP).

0
0 233
Artículo Mathew Lambert · oct 14, 2020 1m read

Esto lo escribo más para ayudar a mi memoria que para otra cosa. Pensé en compartirlo, porque a menudo aparece en los comentarios, pero no está en la documentación de InterSystems

Hay una utilidad increíble que se llama ^REDEBUG, que aumenta el nivel de información que se registra en mgr\cconsole.log. 

Para activarla:

a) inicia el terminal/login

b) zn "%SYS"

c) do ^REDEBUG

d) cambia el nivel de registro a FFFFFFFF

0
0 154
Artículo Ricardo Paiva · sep 4, 2020 5m read

¡Hola desarrolladores!

La clase %Net.SSH.Session permite conectarse a servidores mediante SSH. Lo más habitual es usarlo con SFTP, especialmente en los adaptadores de FTP entrantes y salientes.

En este artículo se dará un breve ejemplo de cómo conectarse a un servidor SSH usando la clase, se describirá las opciones para autenticar y cómo hacer la depuración cuando surjan problemas.

A continuación un ejemplo de cómo hacer la conexión:

Set SSH = ##class(%Net.SSH.Session).%New()
Set return=SSH.Connect("ftp.intersystems.com")​

Esto crea una nueva conexión, y luego se conecta al servidor SFTP ftp.intersystems.com en el puerto predeterminado. En este punto, el cliente y el servidor han elegido opciones y algoritmos de cifrado, pero ningún usuario ha iniciado sesión aún.

Una vez conectado, podrá elegir cómo realizar la autenticación. Hay tres métodos principales para elegir:

  • AuthenticateWithUsername
  • AuthenticateWithKeyPair
  • AuthenticateWithKeyboardInteractive

Cada uno de estos es un tipo distinto de autenticación. La siguiente es una breve introducción a cada tipo:

AuthenticateWithUsername

Esta usa un nombre de usuario y contraseña.

AuthenticateWithKeyPair

Esta usa un par de claves pública y privada. La clave pública se debe haber precargado en el servidor, y debe contar con la clave privada correspondiente. Si la clave privada está cifrada en el disco, debe introduzir una contraseña para descifrarla en la llamada al método. Nota: nunca envíe su clave privada a otra persona.

Las claves públicas deben estar en formato OpenSSH, y las claves privadas deben estar cifradas con PEM. El formato OpenSSH se ve así:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCfi2Vq+u0rtt2OC84pyrkq1k7WkrS+s76u3a+2gdD43KQ2Z3vSUUfksymJjp11JBZEpOtBVIAy221UKdc7j7Qk6sUjZaK8LIy+bzDVwMyFWgVvQge7EjdWjrJLBRCDXYML6y1Y25XexThkTWSGyXzGNdr+wfIHYn/mIt0hfvrusauvT/9Wz8K2MGAj4BL7UQZpFJrlXzGmewe6++6cZDQQYi0aztwLK798oc9j0LsccdMpqWrjqoU1uANFhYIuUu/T47TEhT+e6M+KFYK5TR998eJTO25IjdN2Tgw0feXhQFF/nngbol0bA4auSPaZQsgokKK+E+Q/8UtBdetEofuV user@hostname

Las claves privadas cifradas con PEM tienen un encabezado en la parte superior del archivo que se ve así:

-----BEGIN RSA PRIVATE KEY-----

y terminan con:

-----END RSA PRIVATE KEY-----

AuthenticateWithKeyboardInteractive

Permite realizar una autenticación de desafío y respuesta. Por ejemplo, podría pedir el código de un uso enviado por mensaje de texto o generado por una aplicación autenticadora de Google. Para usar este tipo de autenticación, deberá escribir una función lambda para manejar la solicitudes de comandos enviadas por el servidor. Puede que vea que algunos servidores usan esto con solo una solicitud de nombre de usuario y contraseña, de una forma que para el usuario se ve idéntica a una autenticación por contraseña. Las marcas de depuración SSH descritas a continuación pueden ayudarle a determinar si eso es lo que está viendo. Un último comentario sobre la autenticación: Si le interesa usar dos formas de autenticación para una única conexión, asegúrese de usar Ensemble/Cache 2018.1+ o cualquier versión de InterSystems IRIS. Esta versión tiene actualizaciones que permiten el uso de múltiples formatos, tales como par de claves y nombre de usuario.

Qué hacer cuando algo sale mal...

Algunos errores comunes que podría encontrarse son:

Error al intentar obtener el banner

Esto podría verse así:

ERROR #7500: SSH Connect Error '-2146430963': SSH Error [8010100D]: Failed getting banner [FFFFFFFF8010100D] at Session.cpp:231,0

Obtener el banner es lo primero que hace un cliente SSH. Si ve este error, debería verificar que se está conectando al servidor correcto y que este es un servidor SFTP.

Por ejemplo: si el servidor es en realidad un servidor FTPS, verá este error. Los servidores FTPS usan SSL, no SSH, y por lo tanto no funcionan con la clase %Net.SSH.Session. Puede usar la clase %Net.FtpSession class para conectarse a un servidor FTPS.

No es posible intercambiar claves de cifrado

Este error podría verse así:

ERROR #7500: SSH Connect Error '-2146430971': SSH Error [80101005]: Unable to exchange encryption keys [80101005] at Session.cpp:238,0

Este error generalmente significa que el cliente y el servidor no pudieron negociar algoritmos de MAC o cifrado. Si ve este error, puede que necesite actualizar ya sea el cliente o el servidor para agregar compatibilidad con nuevos algoritmos.

Si está usando una versión de Ensemble/Caché anterior a la 2017.1, le recomiendo actualizar a InterSystems IRIS o probar con 2017.1 o posterior. La biblioteca libssh2 se actualizó en la versión 2017.1 y se agregaron múltiples algoritmos nuevos.

Puede ver más detalles en los registros provistos por las marcas de depuración que describo a continuación.

Firma inválida para clave pública suministrada

Error [80101013]: Invalid signature for supplied public key, or bad username/public key combination [80101013] at Session.cpp:418

Este error podría ser fácil de malinterpretar. Verá este error si su servidor pidió dos formas de autenticación y usted solo facilitó una. Si ese es el caso, continue y pruebe con la próxima. Es posible que todo se arregle.

Error -37

Puede ver mensajes sobre el error -37. Por ejemplo, aquí está en el registro de depuración:

[libssh2] 0.369332 Failure Event: -37 - Failed getting banner

Siempre que aparezca el error -37, la operación que fracasó volverá a intentarse. Este error no es lo que causó la falla final. Busque otros mensajes de error.

Las marcas de depuración de SSH

Se puede habilitar el registro detallado de conexiones SSH para una conexión mediante las marcas de depuración de SSH. Las marcas se habilitan con el método SetTraceMethod. Este es un ejemplo de una conexión que las usa:

Set SSH = ##class(%Net.SSH.Session).%New()
Do SSH.SetTraceMask(511,"/tmp/ssh.log")  
Set Status=SSH.Connect("ftp.intersystems.com")​ 

El primer argumento de SetTraceMask le indica qué recolectar. Es una representación decimal de bits. 511 solicita todos los bits excepto el 512, y es la configuración usada más comúnmente. Si desea conocer más acerca de cada bit, están enumerados en la documentación de la clase %Net.SSH.Session.

El segundo argumento le indica en qué archivo colocar la información de registro sobre la conexión. En este ejemplo usé el archivo /tmp/ssh.log, pero puede ingresar cualquier ruta absoluta o relativa que quiera usar.

En el ejemplo anterior, solo ejecuté el método Connect. Si su problema está en la autenticación, deberá ejecutar también el método de autenticación correspondiente.

Luego de ejecutar su prueba, podrá buscar información en el archivo de registro. Si no está seguro de cómo interpretar el archivo de registro, el Centro Mundial de Respuesta de Intersystems (WRC) puede ayudar.

0
0 244
Pregunta Robert Cemper · ago 30, 2020

Causado por un conflicto en la asignación del puerto, obtengo esta entrada en messages.log y SMS ya no responde:

08/30/20-12:56:40:714 (15232) 1 [Utility.Event] Private webserver may not start on port 52773, may be in use by another instance
08/30/20-12:56:40:737 (15232) 0 [Utility.Event] Private webserver started on 52773

La primera línea es correcta,
La segunda es solo ilusión. sad "Fake News"

¿Cómo puedo reiniciar mi servidor SMP sin una secuencia de reinicio / parada completa de IRIS? 

¿Principalmente en WINDOWS?

1
0 133
Artículo Dani Fibla · jun 26, 2020 6m read

Introducción: nuestra pequeña pero muy ambiciosa empresa llamada “Black Mushroom Studio” tuvo una idea para desarrollar un proyecto de comercio electrónico, y una aplicación móvil que permitiría a los usuarios pagar por ciertos bienes/servicios mediante un agregador de pagos.

Lo que teníamos inicialmente: un esqueleto para la aplicación en Android que, por supuesto, prefería la comunicación mediante HTTP y JSON, y un sistema de pago con una API, es decir, servicios web con contenido SOAP.

Objetivo: hacer que todo funcionara de manera conjunta.

0
0 179
Artículo Jose-Tomas Salvador · jun 25, 2020 2m read

¡Hola desarrolladores de ObjectScript!

How to Protect Your Belongings from Pests While Moving - Delicate ...

InterSystems ObjectScript es probablemente el mejor lenguaje del mundo para trabajar con globals - y es un lenguaje interpretado.

Sí, tiene un compilador. Pero incluso el compilador puede dejar escapar y compilar algunas líneas en ObjectScript que después generen error en tiempo de ejecución.

Hay algunas técnicas para evitarlo tales como los tests unitarios, guías de programación y, por supuesto, ¡tu experiencia programando! ;) 

Aquí quiero presentarte otra alternativa más para que puedas reducir el número de errores de ejecución de tu ObjectScript y reforzar la aplicación de tus guías de programación - se trata de la herramienta de Calidad de ObjectScript desarrollada por Lite Solutions, un partner de InterSystems.

Más detalles  a continuación.

0
0 173
Artículo Mathew Lambert · jun 15, 2020 7m read

Esta es una guía para principiantes, para el desarrollo de servicios web RESTful con Ensemble.

Contexto

Antes de comenzar a leer esta breve introducción, lee la documentación de Ensemble, prestando especial atención al capítulo sobre creación de servicios y clientes REST con Ensemble (“Creating REST services and clients with Ensemble”)

El enfoque de esa documentación creo que es indiscutiblemente la forma más rápida y simple de crear servicios RESTful. Como principiante, leí la documentación y me quedaron varias dudas. Este breve artículo enumera esas preguntas, junto con mis humildes respuestas

0
0 400