
En la última parte del artículo vamos a revisar las opciones que tenemos para extender nuestras aplicaciones de Velneo conectando con el mundo de Internet y las aplicaciones web.
En general hablaremos de aplicaciones web como aquellas herramientas que podemos usar para conectarnos a un servidor web, a través de Internet o de una intranet mediante un navegador.
La red Internet usa la familia de protocolos TCP-IP para interconectar e implementar aplicaciones de todo tipo y hoy en día no hay servicio que no tenga su versión para Internet.
El protocolo VATP, usado para conectar los componentes de Velneo entre sí, también pertenece a la familia de protocolos TCP/IP y por lo tanto también podemos desplegar nuestras aplicaciones Velneo en Internet.
De la misma manera que vClient conecta con vServer a través del protocolo VATP, las aplicaciones web intercambian información con el servidor web usando el HTTP (Protocolo de Transferencia de Hipertexto).
Por lo tanto, al igual que hemos hecho con las funciones remotas y el driver ODBC, necesitamos conectar nuestra Instancia de Velneo, que solo entiende comandos VATP, con una aplicación externa usando el protocolo HTTP.
Veamos entonces qué opciones tenemos los desarrolladores para establecer un puente entre los dos protocolos y conectar nuestras aplicaciones de manera sencilla al universo web.
De forma nativa, Velneo proporciona el objeto Protocolo TCP-IP con el fin de implementar un protocolo de comunicaciones TCP/IP propio en nuestras aplicaciones.
De este objeto nos interesa el subobjeto SERVER y el proceso asociado en el que, mediante los comandos de Protocolo TCP, programaremos el parseo de los mensajes HTTP que continen las partes REQUEST y RESPONSE intercambiadas con el cliente externo.
Para ejecutar el protocolo TCP en el servidor, añadimos al proyecto un proceso con el identificador ON_INIT_SERVER en el que escribimos un comando Protocolo TCP: iniciar servicio. Esto iniciará el servicio TCP en el vServer, escuchando en el puerto especificado en el objeto protocolo TCP del proyecto.
Si usamos un monitor de puertos veremos cómo el proceso vServer.exe está escuchando en 2 puertos. En la imagen siguiente vemos el puerto 690 para el protocolo VATP y el 54240 para el protocolo HTTP que usará el objeto protocolo TCP.

El protocolo TCP estará en funcionamiento en el servidor vServer hasta que se ejecute un comando Protocolo TCP: terminar servicio desde un proceso en tercer plano.

El objeto Protocolo TCP se puede iniciar desde un proceso tanto en primer plano como en el tercer plano.
Veamos un ejemplo básico de cómo programar el intercomunicador SERVER del protocolo TCP para que funcione como un proceso web, encargado de convertir un mensaje HTTP en los comandos VATP que entiende el servidor vServer de Velneo.
El código lee y parsea el Request del mensaje HTTP usando el comando Protocolo TCP: Recibir línea.
Del parseo del Request se obtienen las 4 partes siguientes del mensaje HTTP:
Una vez analizado el Request, el proceso web enviará los comandos de ejecución a la Instancia de datos usando el protocolo VATP. Con el resultado devuelto por la Instancia de datos el proceso web construye el Response y devuelve el mensaje al cliente HTTP.
La petición GET para este ejemplo tendrá el siguiente aspecto:
http://dominio:puerto/?funcion=[FUNCION]&datos=[DATOS]
El parámetro funcion determina la función remota que se va a ejecutar y el parámetro datos indica el formato de los datos devueltos, json o csv.
En la primera parte del artículo utilizamos el componente vClient sin GUI para ejecutar funciones remotas desde una aplicación externa. Con este proceso web conseguimos lo mismo, habilitar la ejecución de funciones remotas desde un cliente HTTP.
// Rem ( Proceso web - Intercomunicador SERVER del objeto Protocolo TCP )
// Rem ( El proceso se ejecuta cuando se recibe una petición TCP-IP al puerto de escucha )
Rem ( La petición tendrá un formato de Mensaje HTTP )
Set ( LDATOS_RESPONSE, 1 )
Set ( CRESUL, “0” )
// Rem ( LÍNEA DE INICIO con la Petición del Mensaje HTTP )
Protocolo TCP: Recibir línea ( HTTP_LINEA_INI, 1 )
// Rem ( PARÁMETROS. Leemos los parámetros del Mensaje HTTP )
Set ( HTTP_PARA_FUN, getStringRegExp(HTTP_LINEA_INI, "funcion=([a-zA-Z\\d\\_]*)", 0, 0, 1) )
Set ( HTTP_PARA_DATOS, getStringRegExp(HTTP_LINEA_INI, "datos=([a-zA-Z,\\d\\_]*)", 0, 0, 1) )
// Rem ( CABECERAS HTTP )
Set ( LSEGUIR, 1 )
For ( NLIN, 0, LSEGUIR, 1 )
Protocolo TCP: Recibir línea ( CLINEA, 1 )
Set ( HTTP_CABECERAS, HTTP_CABECERAS + CLINEA )
If ( CLINEA = "\r\n" )
// Rem ( LÍNEA VACÍA )
Set ( LSEGUIR, 0 )
Set ( HTTP_REQUEST, HTTP_LINEA_INI + HTTP_CABECERAS )
// Rem ( CUERPO DEL MENSAJE. Existe si el verbo es POST o PUT )
If ( indexOfString("POST,PUT ", left(HTTP_LINEA_INI, 4), 0, 0) > -1 )
Rem ( Tamaño del Cuerpo del mensaje )
Set ( HTTP_CUERPO_LONG, stringToNumber(getStringRegExp(HTTP_REQUEST, "Content-Length: (\\d*)", 0, 0, 1)) )
Protocolo TCP: Recibir buffer ( HTTP_DATOS, HTTP_CUERPO_LONG, 3 )
Set ( HTTP_REQUEST, HTTP_REQUEST + HTTP_DATOS )
Libre
// Rem ( RESPONSE. Respuesta que enviamos al cliente HTTP )
// Rem ( LÍNEA DE INICIO de la Respuesta al Mensaje HTTP )
Set ( HTTP_RESPONSE, "HTTP/1.0 200 OK\r\n" )
Rem ( Devolver un Estado 400 en caso de error - Request erróneo )
// Rem ( EJECUTAR PROCESO. Depende del parámetro )
Set ( LRESUL_JSON, HTTP_PARA_DATOS = "json" )
If ( HTTP_PARA_FUN = "ART" )
Rem ( Lista de Artículos desde vGestion - http://<dominio>:puerto/?funcion=ART&datos=json|csv )
Set ( CRESUL, rfc: FUN_REM_ART(_CSERVIDOR, _CINSTANCIA, _CUSUARIO, _CPASSWORD, LRESUL_JSON) )
Else if ( HTTP_PARA_FUN = "CLT" )
Rem ( Lista de Clientes desde vGestion - http://<dominio>:puerto/?funcion=CLT&datos=json|csv )
Set ( CRESUL, rfc: FUN_REM_CLT(_CSERVIDOR, _CINSTANCIA, _CUSUARIO, _CPASSWORD,LRESUL_JSON) )
Else if ( HTTP_PARA_FUN = "VTA_FAC_CLT" )
Rem ( Facturas de Venta de un Cliente - http://<dominio>:puerto/?funcion=VTA_FAC_CLT> )
Rem ( El ID del Cliente se obtiene del cuerpo del mensaje - parámetro id_clt en el POST )
Set ( HTTP_PARA_DATOS, getStringRegExp(HTTP_DATOS, "id_clt=([a-zA-Z,\\d\\_]*)", 0, 0, 1) )
Set ( CRESUL, rfc: FUN_REM_VTA_FAC_CLT(_CSERVIDOR, _CINSTANCIA, _CUSUARIO, _CPASSWORD, HTTP_PARA_DATOS) )
Else if ( HTTP_PARA_FUN = "CSS" )
Rem ( Descarga la Hoja de Estilo. El parámetro contiene el ID- http://<dominio>:puerto/?funcion=CSS)
Set ( CRESUL, rfc: HOJA_ESTILO(_CSERVIDOR, _CINSTANCIA, _CUSUARIO, _CPASSWORD, HTTP_PARA_DATOS) )
Else if ( HTTP_PARA_FUN = "IMG_CSS" )
Rem ( Descarga la Lista de Imágenes CSS - http://<dominio>:puerto/?funcion=IMG_CSS&datos=json )
Set ( CRESUL, rfc: FUN_CSS_IMG_EXPORTAR(_CSERVIDOR, _CINSTANCIA, _CUSUARIO, _CPASSWORD, HTTP_PARA_DATOS) )
Libre
Rem ( El 0 se considera ERROR )
If ( CRESUL = "0" )
Set ( LRESUL_JSON, 0 )
Set ( CRESUL, "##ERROR## ejecutando la Función remota FUN_REM_" + HTTP_PARA_FUN )
Set ( HTTP_RESPONSE, "HTTP/1.0 400 BAD REQUEST\r\n" )
Libre
If ( LDATOS_RESPONSE = 1 )
// Rem ( CABECERAS. Tamaño de la Respuesta y tipo de contenido de los DATOS )
Rem ( Datos codificados en UTF-8 (Header charset=UTF-8) )
Set ( CRESUL_UTF8, stringToAscii(CRESUL, "UTF-8") )
Set ( NRESUL_LEN, len(CRESUL_UTF8) )
Set ( HTTP_RESPONSE, HTTP_RESPONSE + "Content-Length: " + NRESUL_LEN + "\r\n" )
Set ( HTTP_RESPONSE, HTTP_RESPONSE + "Content-Type: " + choose(LRESUL_JSON, "application/json", "text/plain") + "; charset=UTF-8\r\n" )
// Rem ( LÍNEA VACÍA )
Set ( HTTP_RESPONSE, HTTP_RESPONSE + "\r\n" )
// Rem ( DATOS con el Resultado )
Set ( HTTP_RESPONSE, HTTP_RESPONSE + CRESUL_UTF8 )
Libre
// Rem Envía el Response al cliente HTTP
Protocolo TCP: Enviar buffer ( HTTP_RESPONSE, len(HTTP_RESPONSE), 10 )
Libre
La imagen siguiente muestra el resultado de un mensaje HTTP con el comando GET. Se solicita la ejecución de la función remota ART con el formato de salida JSON. Como cliente HTML se ha usado el Visor HTML nativo de Velneo.

Para montar un servidor HTTP en Velneo Cloud hay que solicitar a Velneo el servicio TCP en Cloud. Tendrás disponible un conjunto de puertos para usar en las peticiones HTTP.
Por ejemplo http://c3.velneo.com:10193/?funcion=ART&datos=csv.
Con este sencillo código tenemos nuestro primer proceso web preparado para intercambiar información con cualquier aplicación externa a través del protocolo HTTP. Nuestra herramienta de análisis de datos Excel ya puede descargar información de la Instancia de datos con una simple consulta Web.

Este sería el funcionamiento básico de un servidor HTTP, pero por supuesto necesitamos muchas más funcionalidades si pretendemos poner en producción nuestra aplicación conectada a un entorno web público.
Afortunadamente Cristian Vásquez ha desarrollado CIRRUS y lo ha puesto al servicio de la comunidad de desarrolladores de Velneo. Es una Open App con una calidad técnica de primer orden, que podemos usar con total garantía.
Cirrus se autodefine como una implementación en JavaScript del protocolo HTTP corriendo directamente sobre el objecto TCP/IP de Velneo V7, que permite servir código HTML, JSON, Javascript y CSS directamente desde una app Velneo v7.
El esquema de funcionamiento de Cirrus se basa en un modelo de tres componentes denominados Rutas, Controladores y Renderizado.

Todo el código de CIRRUS reside en el archivo javascript cirrus.js, en el que se define el objeto global wAPP y toda la lógica de parseo y renderizado a partir del mensaje HTTP.

En el archivo api_server.js se establecen las rutas y controladores y finalmente se procesa el Request renderizando el Response correspondiente.
Las rutas son el intermediario entre las peticiones HTTP y la lógica de negocio que se encuentra en los controladores de la aplicacción.
Las rutas se añaden a la propiedad router de wAPP mediante la función addRouters().
Cada método de petición HTTP se dirige a un controlador con la acción correspondiente, separados por un caracter de almohadilla #. También podemos mapear directamemte objetos nativos de Velneo de tipo Procesos y Búsquedas.
En el código siguiente añadimos las rutas para las tablas de Clientes y Artículos. Las rutas envían la petición del mensaje HTTP a los controladores cltController y artController respectivamente.
wApp.router.addRoutes({
// Clientes
"GET /clt": "cltController#index",
// Artículos. La Ruta resource crea las 7 rutas REST
/*
Los parámetros se marcan con los dos puntos o de la forma habitual param=valor
En el body los parámetros se introducen en formato URL encoded
GET /art "artController#index" Lista de artículos
GET /art/:id "artController#show" Mostrar un artículo
PUT /art/:id "artController#update" Actualizar un articulo desde el Body
POST /art "artController#create" Crea un articulo desde el Body
DELETE /art/:id "artController#delete" Eliminar un artículo
GET /art/new "artController#new" Nuevo artículo (con formulario HTML)
GET /art/:id/edit "artController#edit" Editar un artículo (con formulario HTML)
*/
"resource art": "art",
// Procesos y Querys. Extensión .pro y .bus
// El resultado se devuelve en la variable local RESULT
// Si no existe RESULT se devuelve vRegisterListToJSON de la salida del proceso
// Se puede pasar la lista de campos en el parámetro ?fields=id,name,...
"GET /art.pro": cAlias_dat + "/PRO_HTTP_ART",
"GET /art.bus": cAlias_dat + "/BUS_HTTP_ART",
});
Los controladores son los mediadores entre los Mensajes HTTP y el acceso a los datos. El controlador es el código que accede a la Instancia de datos para devolver una respuesta usando un objeto JSON.
El controlador se añade a wAPP como un objeto javascript con el nombre del controlador seguido de la palabra Controller. Las acciones del controlador se definen como funciones del controlador.
A continuación tienes el código del controlador artController, con las acciones de Listar, Mostrar, Editar, Añadir y Eliminar artículos.
wApp.artController = {
// LISTA de artículos
// Usar GET -> http://dominio:puerto/art[.json]
"index": function(params) {
return ({articulos: getArt()});
},
// MOSTRAR un Artículo - GET -> http://dominio:puerto/art/:ID[.json]
// params es un json con el :ID de la URL
"show": function(params){
var registros = new VRegisterList(theRoot);
registros.setTable("vgestion_dat/ART");
registros.load("ID", [params.id]);
var aCampos = "ID,NAME,FAM,REF,COD_BAR,PRE_VTA".split(",")
return (wApp.vRegisterListToJSON(registros, aCampos));
},
// EDITAR un Artículo - PUT -> http://dominio:puerto/art/:ID
// params es un json con el :ID de la URL y con los
// datos del Body como urlencoded - name=NOM_ART&ref=REF_ART
"update": function(params) {
if ( theRoot.beginTrans("Transacción en Mensaje HTTP - Modificar artículo")) {
var registros = new VRegisterList(theRoot);
registros.setTable("vgestion_dat/ART");
registros.load("ID", [params.id])
var articulo = registros.readAt(0)
articulo.setField("NAME", params.body.name)
articulo.setField("REF", params.body.ref)
articulo.modifyRegister()
theRoot.commitTrans();
}
return ({message: "Artículo modificado"})
},
// CREAR un nuevo Artículo - POST -> http://dominio:puerto/art
// params es un json con los datos del Body como urlencoded - campo1=valor2&campo2=valor2
// con Header --> Content-Type: application/x-www-form-urlencoded
"create": function(params) {
if ( theRoot.beginTrans("Transacción en Mensaje HTTP - Nuevo artículo")) {
var articulo = new VRegister(theRoot);
articulo.setTable("vgestion_dat/ART");
articulo.setField( "NAME", params.body.name);
articulo.setField( "REF", params.body.ref);
articulo.setField( "FAM", params.body.fam);
articulo.setField( "COD_BAR", params.body.cod_bar);
// Se guarda el registro
articulo.addRegister();
theRoot.commitTrans();
}
return ({message: "Nuevo artículo: " + articulo.fieldToInt("ID")});
},
// ELIMINAR un Artículo - DELETE -> http://dominio:puerto/art/:ID
// params es un json con el :ID de la URL
"delete": function(params) {
if ( theRoot.beginTrans("Transacción en Mensaje HTTP - Eliminar artículo")) {
var registros = new VRegisterList(theRoot);
registros.setTable("vgestion_dat/ART");
registros.load("ID", [params.id])
var articulo = registros.readAt(0)
articulo.deleteRegister()
theRoot.commitTrans();
}
return ({message: "Artículo eliminado"})
}
}
Los controladores pueden ser ampliados con características opcionales como filtros, autenticación básica y cabeceras personalizadas.
El módulo Renderizador recoge la salida del Controlador y entrega un Response con los datos en el formato solicitado por la parte Request del mensaje HTTP. Por defecto la salida es json y además podemos obtener html, xml o css.
Veamos algunos ejemplos que devuelven exclusivamente json:
Listar la tabla de artículos
http://c3.velneo.com:10194/art.json
Mostrar el artículo con ID igual a 23
http://c3.velneo.com:10194/art/23.json
Pasar un parámetro al proceso
http://c3.velneo.com:10194/art.pro?id=23
Método PUT. Actualizar el artículo con ID = 23
http://c3.velneo.com:10194/art/23
Body: name=Nuevo ART&ref=REF NUEVA
Para facilitar y ampliar el renderizado de código html, Cirrus implementa opcionalmente un sistema por el cual una Acción del Controlador se asocia a una Vista, la cual define una plantilla o template en la que podemos incrustar la salida del controlador, preprocesando el json mediante la herramienta Handlebars. Puedes ampliar información en la documentación de cirrus.
En el servidor HTTP que hemos visto hasta ahora, el proceso web (intercomunicador SERVER) es cargado y ejecutado en cada petición del cliente HTML, debido a la forma en que Velneo implementa el objeto Protocolo TCP. Por lo tanto, puede que no reuna los requisitos de eficiencia, seguridad y concurrencia que se necesita en un entorno público de internet.
Velneo, desde sus inicios, no se ha planteado la opción de incorporar un servidor HTTP dentro de vServer, en su lugar se optó por aprovechar la tecnología de un servidor Web externo.
Separar el servidor HTTP del servidor VATP permite asegurar nuestros datos ante cualquier ataque, como el de denegación de servicio, ya que no afectará al vServer y será el servidor Apache el que recibe todo ese tráfico.
Para conseguir el objetivo de facilitar la conexión de nuestras aplicaciones web externas con la instancia de datos de vServer a través del protocolo HTTP, Velneo tuvo que resolver tres aspectos:

El servidor Apache es una opción fiable y muy utilizada entre los servidores web disponibles en Internet. Es una plataforma estable y robusta con un desarrollo continuo por parte de la Apache Software Foundation.
Para nuestras pruebas en local disponemos de varios paquetes compilados de Apache, que además instalan PHP y MySQL. Uno de los paquetes más habituales es Bitnami WAMP Stack.
Velneo requiere una versión 2.4.X de Apache con soporte de OpenSSL 1.1.
El módulo vModApache se ha diseñado como puente entre los mensajes HTTP de Apache y el servidor vServer. Nos permitirá enviar comandos VATP a nuestra instancia de aplicación de vServer usando el protocolo HTTP de la Web.
Es un componente equivalente a vClient, pero sin GUI, y por lo tanto dispone de todas las ventajas de este componente, como la caché de datos en memoria y el refresco terciario, así como la caché local de archivos a nivel de usuario.
El servidor Apache usará el módulo vModApache en multitarea y con múltiples vServer. La configuración determina cuantos enganches puede establecer vModApache y los límites, dependiendo del número de conexiones simultáneas que queramos soportar.
La instalación de vModApache copia el archivo mod_velneo.so en el directorio de Velneo por defecto %programfiles%\Velneo, de esta forma tiene acceso a las librerías Qt necesarias.
La instalación de vModApache se puede realizar en los sistemas operativos de Windows y Linux. En Windows la versión de 32 o 64 bits coincidirá con la del servidor Apache.
Para que el servidor Apache pueda usar el módulo vModApache debemos especificar la ruta en el archivo de configuración de directivas conf/httpd.conf.
#Carga el módulo de Velneo
LoadModule velneo_module "C:/Archivos de programa/Velneo/mod_velneo.so"
La conexión del módulo vModApache al servidor vServer se configura en la directiva Location o también en la directiva Virtualhost. Al igual que vClient, el módulo vModapache solo se puede conectar a instancias de aplicación y accederá al resto de proyectos de la solución a través de la herencia.
# La directiva Location define un subdirectorio o ruta_base en nuestro dominio web
# https://nombre_servidor/ruta_base/recurso.pro
<Location /ruta_base>
setHandler velneo
[VelneoMode SERVER]
Vrl vatp[/s]://usuario:contraseña@servidor[:NUM_PUERTO]/ID_INSTANCIA_APP
</Location>
# La directiva VirtualHost redirige un puerto a un dominio
# https://nombre_servidor/recurso.pro
<VirtualHost *:número_puerto>
ServerName nombre_servidor
[VelneoMode SERVER]
setHandler velneo
Vrl vatp[s]://usuario:contraseña@servidor[:NUM_PUERTO]/ID_INSTANCIA_APP
</VirtualHost>
Cuando se inicia el servidor Apache la directiva Location o VirtualHost ejecuta la conexión con el vServer usando la VRL del protocolo VATP. Se creará un enganche a la instancia de la aplicación ID_INSTANCIA_APP con el usuario y contraseña indicados. A partir de entonces todas las peticiones HTTP a través de la senda ruta_base o número_puerto de la URL se encolan por vModApache al enganche establecido en vServer contra la instancia de aplicación.

Cuando aparece la opción VelneoMode SERVER, los procesos web se ejecutarán en el tercer plano. De la misma manera que hacemos en vClient con el comando Ejecutar proceso, vModApache dispone de la opción de 1P o 3P. Los procesos en 1P pueden usar el GUI, como por ejemplo el comando Exportar informe a fichero (solo en windows).
Las tablas en memoria que se usan en local desde vModApache, serán compartidas por todas las llamadas sucesivas que usen el mismo enganche. Lo mismo ocurrirá con las variables globales en memoria.
El módulo vModApache crea una caché de archivos local en la carpeta cacherun dentro del perfil de usuario. El usuario con el que se ejecuta vModApache es el usuario asignado al servicio Apache.
En windows, por defecto el usuario es system y la cacherun se crea en la carpeta:
C:\Windows\System32\config\systemprofile\Velneo\cacherun\<ip_vServer>
En Cloud la caché local se crea en
//Velneo/cacherun/localhost_<puerto>/
Más detalles de la configuración de vModApache en la documentación de Velneo
Velneo proporciona en su Cloud el servicio Velneo Cloud vModApache que incluye la combinación servidor Apache y módulo vModApache junto al servidor vServer.
La URL de acceso al servidor Apache se utiliza usando el protocolo seguro https. Velneo proporciona los certificados autofirmados para las pruebas de nuestra aplicación.

Mediante SFTP podemos acceder a las carpetas de Apache y al fichero de configuración 001-default-ssl.conf

# Configuración de Velneo Cloud vModApache
# Logs del servidor Apache
CustomLog /home/${USERNAME}/apache2/logs/access.log combined
ErrorLog /home/${USERNAME}/apache2/logs/error.log
# Servidor Apache en el puerto seguro 443
<VirtualHost *:443>
DocumentRoot /home/${USERNAME}/apache2/html
<Directory /home/${USERNAME}/apache2/html/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# Certificados autofirmados
SSLCertificateFile /etc/apache2/external/cert.crt
SSLCertificateKeyFile /etc/apache2/external/cert.key
ServerName c3.velneo.com
<Location /miapp>
setHandler velneo
[VelneoMode SERVER]
# VRL de acceso a la instancia de aplicación en el cloud
Vrl vatps://<usuario>:<contraseña>@localhost:10190/INSTANCIA_APP
</Location>
</VirtualHost>
La recomendación de Velneo es instalar una combinación de Apache/vModApache única por cada instancia que vayamos a usar con la aplicación externa web.
Hay varias incidencias con VModApache en Cloud a tener en cuenta:
Comando Informe: Exportar a fichero PDF no funciona en Linux
La función setRawBody() de theResponse no funciona en Modo normal
Carpeta cacherun (sysCacheClientPath) no funciona en Modo normal
Un cliente HTTP externo puede tener acceso a través de vModApache a los siguientes objetos de nuestros proyectos de Velneo:
Los procesos nativos y javascript deben tener el estilo Accesible web activado (a partir de ahora los llamamos también procesos web). Los procesos web nativos devuelven información con el comando Set dato de retorno y los procesos web javascript disponen para este cometido del objeto API theResponse.
El comando Set dato de retorno solo es operativo en los objetos función, tal como confirma la documentación, y es curioso que solo sea funcional en los procesos web.
Los procesos web nativos pueden recibir parámetros que se asignarán automáticamente a las variables locales del mismo nombre. Los procesos web de javascript usarán el objeto del API theRequest para obtener las claves del GET o del POST.
La codificación del texto devuelto desde los procesos nativos (ISO-8859-1, UTF-8, ...) se determina mediante la variable local CONTENT_TYPE en la que introducimos el valor de la cabecera Content-Type del Response. Los procesos javascript harán uso del objeto theResponse y la función setContentType().
Por ejemplo, los procesos que devuelven JSON tienen que incluir una línea como la siguiente:
proceso nativo - Set ( CONTENT_TYPE, "application/json; charset=UTF-8")
proceso javascript - theResponse.setContentType("application/json; charset=UTF-8")
Existe una incidencia con la variable local CONTENT_TYPE cuando el proceso se ejecuta en tercer plano (directica VelneoMode SERVER). En ese contexto el proceso nativo no devuelve la cabecera con la codificación del texto.
Si el proceso devuelve código HTML usaremos un elemento meta con atributo charset en la etiqueta <head>.
<head>
<meta charset='UTF-8'>
<title>...</title>
</head>
Los Dibujos estáticos son de solo lectura declarados en los proyectos. Se pueden obtener en formato jpg y png. El formato png conserva el canal alfa con la transparencia.
Son campos con contenido gráfico en las tablas del proyecto de datos. Están almacenados en el archivo contenedor cnd de la base de datos, con compresión JPEG al 100% de calidad.
Los ficheros adjuntos del proyecto se copian a la carpeta de caché de archivos (cacherun), localizada en el perfil del usuario que ejecuta el cliente vModApache. Los procesos ejecutados en local (sin la directiva VelneoMode SERVER) disponen de la variable del sistema sysCacheClientPath con la que tendrán acceso a los archivos adjuntos en la carpeta cacherun.
Los procesos que devuelven código HTML pueden usar enlaces relativos a la carpeta DocumentRoot del servidor Apache. Cada directiva Virtualhost puede tener su propio DocumentRoot.
Desde el cliente HTTP usaremos las siguientes URL's para acceder a los recursos de la aplicación Velneo.
La URL base de todos los recursos desde Velneo es http[s]:dominio/Location/.
| Objeto | URL |
|---|---|
| URL base | http[s]:dominio/Location/ (busca index.[pro] si existe) |
| Proceso | [Id_Proyecto_ext]/[proceso][.pro]?par1=val1&par2=val2.. |
| Dibujo | [Id_Proyecto_ext]/Id_dibujo.[jpg][png] |
| Campo Dibujo | obj/[Id_Proyecto_ext]/Id_tabla/#campo.jpg/png |
| DocumentRoot | ../archivo (path relativo a Location) |
Id_Proyecto es el Nombre del proyecto (no el Alias) al que pertenece el objeto y hay que respetar las mayúsculas/minúsculas. Se añade la _ext app o dat en minúsculas para identificar el proyecto de aplicación a de datos. No es necesario indicar esta parte de la URL cuando el proceso es del proyecto principal indicado en la VRL de conexión.
El nombre del proceso es el endpoint final que llevará opcionalmente la extensión .pro. Si no se especifica se buscará en el proyecto un proceso con identificador INDEX.
Los nombres de los parámetros deben coincidir con Variables locales del proceso.
Los dibujos estáticos se descargan directamente con el identificador, seguido de la extensión que determina el formato jpg o png.
Id_dibujo es el identificador del objeto dibujo en el proyecto principal o heredado.
El contenido de los campos de tipo dibujo se obtiene usando el prefijo especial obj/. El formato puede ser jpg o png. El prefijo obj/ indica que se trata de un campo objeto y es obligatorio.
Id_tabla es el identificador de la tabla en el proyecto de datos.
El valor del campo de tipo dibujo #campo corresponde al contenido en el archivo .dat y es un puntero o etiqueta que apunta a la imagen jpeg archivada en el contenedor .cnd de la base de datos.
El prefijo obj/ solo funciona para proyectos de datos que heredan directamente del proyecto principal. En el esquema de la imagen siguiente, para acceder a un campo de la tabla en vgestion_dat, habrá que crear una rama de herencia entre el proyecto principal y el proyecto de datos vgestion_dat. VDevelop nos marcará esta herencia como redundante.

Cuando la aplicación Velneo sirve código HTML al cliente web, éste renderiza el HTML teniendo en cuenta que los enlaces toman como carpeta base la URL base http[s]:dominio/Location/.
Si queremos servir un archivo de la carpeta principal de Apache usaremos la ruta relativa.
<img src='../mi_logo.png'></img>
En el siguiente ejemplo se usan los cuatro tipos de enlaces relativos al URL base.
https://c3.velneo.com:10192/miapp/index

La Lista de artículos accede a los dibujos de la tabla a través del prefijo obj/ y de la herencia redundante.
https://c3.velneo.com:10192/miapp/pro_http_art_img

El siguiente paso, para aprovechar todo el potencial de los procesos web y vModApache fue crear en la versión Velneo 7.19 un API REST para estandarizar el acceso de aplicaciones externas a los datos de nuestra aplicación usando el protocolo HTTP.
Un API (Interfaz de Programación de Aplicaciones) es el conjunto de funciones y procedimientos que ofrece una bibliotea o librería para ser utilizada por una aplicación externa como una capa de abstracción.
REST (Transferencia de Estado Representacional) es cualquier interfaz entre sistemas que use HTTP para obtener y manipular datos en todos los formatos posibles, como XML y JSON. Es una alternativa más sencilla a otros protocolos estándar de intercambio de datos como SOAP (Simple Object Access Protocol), mucho más complejos. RESTful es un servicio web que implementa la arquitectura REST.
Las características principales del API Rest de Velneo son las siguientes:
Es Estándar porque está basado en la sintaxis jsonapi.org con respuestas json. La cabecera ContentType de las respuestas siempre es "application/json; charset=utf-8".
Seguridad implementada en cuatro niveles: protocolo https a través de Apache, uso de API Key, objetos privados y sistema de permisos por objetos.
A los recursos indicados en la URL se aplican operaciones de listado, modificación y borrado a través de los métodos GET, POST y DELETE respectivamente. En otras aplicaciones se usa el método PATCH para actualizar y PUT para reemplazar.
Autodocumentado con Swagger. Usando Swagger UI para exponer la documentación de nuestra API podemos organizar nuestros métodos y probar los diferentes métodos HTTP.

El módulo API Rest de Velneo viene incluido en la plantilla de código abierto vERP. La documentación del API Rest la encontrarás en la parte correspondiente a vERP.
El módulo principal del API Rest de Velneo se ha programado en un solo proceso web llamado V1. El proceso V1 usa los procesos javascript v1.js y api_rest_funciones_v1.js.
Tiene las siguientes funcionalidades:
El proceso web V1 recibe el objeto theRequest de la petición HTTP desde vModApache, lo parsea y obtiene las diferentes partes de la URL. Se ejecuta el método HTTP sobre el recurso solicitado, obteniendo una lista en formato JSON, que se envía al objeto de salida theResponse.
La URL con la petición al API Rest se compone de las siguientes partes:

En el proceso V1 existe un objeto global uriObjeto con todos los componentes de la URL y la configuración de acceso y seguridad.
| Propiedad | Valor |
|---|---|
| api_key | API key de acceso al recurso |
| metodo | GET | POST | DELETE |
| recurso | <nombre tabla> | _process | _requery |
| tabla | Identificador alias_proyecto/id_tabla |
| proceso | Identificador alias_proyecto/id_proceso |
| busqueda | Identificador alias_proyecto/id_busqueda |
| identificador | ID de tabla | id_proceso | id_busqueda |
| fields_tablas | Array - Parámetro fields |
| fields_campos | Array - Parámetro fields=campo1,camp2, ... |
| sort | Array - Parámetro sort=campo1,camp2, ... |
| filter | Array - Parámetros filter[índice]=valor |
| page | Parámetro page[number] y page[size] |
| param | Parámetro param[var local]=valor |
| body | Método POST - Contenido JSON del Body |
| errores | Array - Mensajes de error |
| seg_metodos | Array - Métodos HTTP soportados |
| seg_campos | Array - Campos devueltos de la tabla |
| seg_procesos | Array - Procesos con o sin salida de la tabla |
| seg_busquedas | Array - Búsquedas de la tabla |
El recurso solicitado en la URL se busca en la herencia de todos los proyectos de la Solución, por lo tanto es conveniente que el ID del recurso sea único en toda la herencia.
El API key determina los métodos HTTP que podemos usar, así como los campos, procesos y búsquedas asociados a la tabla que serán accesibles a través de la URL.
Para el método POST los datos del Body se reciben en la variable local BODY del proceso. Los campos de tipo Objeto Dibujo reciben el contenido codificado en Base64.
Veamos algunos ejemplos:
Todos los registros de la tabla vgestion_dat/ART, con page[size]: 20.
https://c3.velneo.com:10192/miapp_server/v1/art?page[size]=20&api_key=apiVelneo
Tabla vgestion_dat/ART, sort: PRE_VTA (desc), filter: [fam]=F2.
https://c3.velneo.com:10192/miapp_server/v1/art?sort=-pre_vta&filter[fam]=F2&api_key=apiVelneo
Tabla vgestion_dat/ART, ID: 234, 300, fields: id,name,pre_vta.
https://c3.velneo.com:10192/miapp_server/v1/art/234,300?fields=id,name,pre_vta&api_key=apiVelneo
Método DELETE. Tabla vgestion_dat/ART, eliminar los registros con ID 1001 y 1002.
https://c3.velneo.com:10192/miapp_server/v1/art/1001,1002?api_key=apiVelneo
Método POST. Tabla vgestion_dat/ART, añadir registro.
body: {"name": "Nuevo ART", "fam": "F2", "ref": "REF-NUEVO", "pre_vta": 3333 }
https://c3.velneo.com:10192/miapp_server/v1/art?api_key=apiVelneo
Método POST. Tabla vgestion_dat/ART, modificar registros con ID 850 y 950.
body: {"name": "ART Modificado", "fam": "F5", "ref": "REF-MODIFICADO", "pre_vta": 1234 }
https://c3.velneo.com:10192/miapp_server/v1/art/850,950?api_key=apiVelneo
Proceso PRO_REST_ART con salida vgestion_dat/ART.
https://c3.velneo.com:10192/miapp_server/v1/_process/pro_rest_art?api_key=apiVelneo
Búsqueda BUS_REST_ART con salida vgestion_dat/ART.
https://c3.velneo.com:10192/miapp_server/v1/_query/bus_rest_art?fields=id,name,ref&api_key=apiVelneo
Hay un problema con la seguridad de acceso que debemos tener en cuenta. El parámetro fields permite el acceso a campos Privados a través de los punteros a Maestro.
El API key determina los métodos HTTP que podemos usar con los procesos sin salida.
Los procesos reciben parámetros en la variables locales y devuelven un resultado JSON personalizado en la variable local RETORNO. Para el método POST los datos del Body se reciben en la variable local BODY.
Proceso PRO_REST_ART_SIN devuelve un JSON personalizado.
https://c3.velneo.com:10192/miapp_server/v1/_process/pro_rest_art_sin?api_key=apiVelneo
Proceso PRO_REST_ART_SIN con un parámetro en la variable local ID.
https://c3.velneo.com:10192/miapp_server/v1/_process/pro_rest_art_sin?param[id]=12&api_key=apiVelneo
El proceso web en Modo Local no funciona cuando en el Path no aparece el nombre del proyecto de Aplicación.
https://c3.velneo.com:10192/miapp/v1/art?api_key=apiVelneo No funciona
https://c3.velneo.com:10192/miapp/0PS_ARTIPACO_app_app/v1/art?api_key=apiVelneo Funciona
Para cumplir con el requisito de ser autodocumentado, el API Rest de Velneo ha desarrollado un proceso web con el nombre SWAGGER, con la misión de generar dinámicamente un fichero de definición del API disponible en la aplicación.
Swagger es una serie de reglas, especificaciones y herramientas que nos ayudan a documentar nuestras APIs.
En nuestra aplicación, la documentación del API Rest es accesible con la url siguiente:
https://c3.velneo.com:10192/miapp_server/swagger?api_key=apiVelneo
El JSON devuelto por el proceso swagger puede ser analizado de forma gráfica mediante la aplicación swagger UI.
Usar la versión 2 de Swagger que es la que usa Velneo.
Descargar Swagger UI desde https://github.com/swagger-api/swagger-ui/releases/tag/v2.2.10.
Copiar la carpeta _dist del zip a una subcarpeta de Apache, por ejemplo /apache2/htdocs/_swagger.
Editar index.html y cambiar el url inicial.
Acceso al Swagger UI en https://c3.velneo.com:10192/_swagger/
La herramienta Swagger UI nos presenta los Recursos disponibles en el API y los parámetros necesarios, así como un ejemplo del URL de acceso a través del proceso web V1.

En esta última parte del artículo hemos explorado las herramientas que Velneo nos proporciona para conectar con aplicaciones externas, usando procesos web y el protocolo HTTP.
De forma nativa disponemos de un servidor HTTP básico con el objeto Protocolo TCP-IP y el subobjeto SERVER. Con Cirrus potenciamos el servidor TCP para facilitar la creación de nuestro propio servicio web, incluso renderizar HTML y llegar a construir un verdadero servidor web. Velneo puede habilitarnos un servicio TCP en Cloud para dar conectividad HTTP a nuestras aplicaciones Velneo a través de Internet.
Para disponer de mayor eficiencia, seguridad y concurrencia en un entorno público de Internet, Velneo ha desarrollado el módulo vModApache para conectar nuestro vServer con el servidor HTTP Apache. Se establece entonces un mecanismo de acceso a los objetos de nuestra Solución desde la web y una estructura de las URL para las peticiones HTTP. Velneo proporciona en el Cloud su servicio Velneo Cloud vModApache.
Finalmente, Velneo pone a nuestra disposición un API Rest que cumple con la especificación jsonapi.org, para que sea un estandar el acceso a nuestros datos desde cualquier aplicación web.
Espero que estos tres artículos os sirvan para conocer qué recursos disponemos desde Velneo para conectar nuestros datos con aplicaciones externas. Desde lo más nativo como las funciones remotas, pasando por módulos específicos como el driver ODBC, hasta llegar a conectar con el mundo web mediante APIs y servidores avanzados como Apache.
Seguiremos explorando nuevas herramientas que nos permitan extender las posibilidades de nuestras aplicaciones Velneo. No os lo perdáis, os espero.
