Saltar a contenido

Json API

El desarrollo de eFlow, no cuenta con un modelo de interfaces API estándar con modelo de tokens y rutas con datos incrustados en las rutas, debido a sus origines de desarrollos muy tempranos en Internet.

Sin embargo se ha echo el esfuerzo de suministrar una interface lo más similar posible y funcional utilizando transacciones HTTP: GET, PUT, DELETE y POST.

Transacciones GET y DELETE

En este caso los parámetros se envían codificados en URL Encoding en el estándar inicial y tradicional agregando los parámetros después de la ruta usando el delimitador de signo de interrogación

curl "https://eflow.empresa.com.mx/api-cgi/eflow/folio?p=2&f=868"

En este ejemplo se llama el punto de entrada de la API con los parámetros : p = 2 y f = 868

Transacciones POST y PUT

Se pueden enviar mensajes completos en el cuerpo del mensaje

curl -X POST https://eflow.empresa.com.mx/cgi/api/getTicket \
-H 'Content-Type: application/json' \
-d '{"account":"usuario","passwd":"contraseña"}'

No se pueden extraer parámetros de rutas url

Todos los parámetros que desee hacer llegar a su implementación deberá ser enviando su objeto JSON el el cuerpo del mensaje o enviando valores pequeños de referencia en el query the un get o delete.

Ejecución de acciones definidas

Debido a que no se cuenta con rutas en el URL para definir acciones a realizar (por ejemplo: agregar, eliminar, actualizar, consultar, etc)

En las llamadas POST se ha creado como estándar adicionar a los datos de la transacción un comando; el cual define la acción a realizar.

curl -X POST https://eflow.empresa.com.mx/cgi/api-bin/eflow/folio \
-H 'Content-Type: application/json' \
-d '{"cmd":"cancel","process":"4","station":"4","folio":"122"}'

Autenticación de APIs

Existen 2 posibles lugares donde colocar sus APIs

APIs para acceso dentro del flujo de eFlow

/home/eflowweb/cgi-bin/api/....

Este es el lugar estándar donde colocar APIs que se van a llamar desde el interior de la misma aplicación de eFlow. Estas rutas están protegidas con un ticket que se asigna al navegador al momento que se realizó el ingreso. Y al estar disponible en el navegador se envía automáticamente en cada transacción a estas rutas y no necesita hacer algún tipo de proceso de registro u obtención de tokens.

La vida del cookie de exceso en esta ruta está vigente mientras el usuario no cierre o salga de la aplicación.

Uso

Normalmente usamos esta para el desarrollo de ventanas emergentes donde usamos tecnologías reactivas de Javascript como Vue, React, etc.

Al colocar nuestras apis en este lugar, las aplicaciones emergentes desarrolladas ya contarán con las credenciales necesarias para conectarse a nuestra api sin necesidad de crear tickets u otro mecanismo de autenticación.

APIs de acceso externo

/home/eflowweb/api-bin/...

Este es el lugar done se deben de instalar y ejecutar APIs que se acceden desde portales externos. Esta ruta también está protegida por un ticket en forma de cookie y deberá enviar el ticket en el cookie : auth_tkt para tener acceso al punto de entrada de la API.

Estas credenciales tienen una vida de 3 minutos y sirven para realizar transacciones únicas en una llamada posterior a una API dentro de la ruta mencionada previamente.

Uso

Estas apis se utilizan normalmente cuando hacemos llamadas desde otros servidores externos.

Obtener token de autenticación temporal

Para obtener un token válido deberá llamar la API, necesitamos crear un POST, con los datos de cuenta y contraseña de un usuario válido de eFlow al punto de entrada siguiente.

curl -X POST https://eflow.empresa.com.mx/cgi/api/getTicket \
-H 'Content-Type: application/json' \
-d '{"account":"usuario","passwd":"contraseña"}'

Respuesta:

{"message":"ticket","data":{"auth_tkt":"NTdm.....XY="},"status":true}

Esto le regresará el token el cual deberá incluir en su transacción posterior en el cookie : auth_tkt

Ejemplo, curl

curl --cookie "auth_tkt=NTdm.....XY=" \
"https://eflow.miempresa.com.mx/api-bin/eflow/folio?p=2&f=868"

Configuración apache

Para que la ruta /api-bin esté disponible, deberá tener configurado en su archivo eflow.conf de apache una sección de directorio similar a la siguiente:

<Directory "/home/installation-path/api-bin">
AllowOverride all
AuthType None
<RequireAny>
Require method OPTIONS
require valid-user
</RequireAny>
TKTAuthLoginURL /public/login.json
TKTAuthTimeoutURL /public/timeout.json
TKTAuthIgnoreIP on
TKTAuthTimeout 180
TKTAuthCookieExpires 180s
Options ExecCGI
SSLOptions +StdEnvVars
</Directory>

Y en la sección de VirtualHost agregar una alías de acceso a la ruta

<VirtualHost *:443>
...
ScriptAlias /api-bin/ "/home/installation-path/api-bin/"
...
</VirtualHost>

API : folio

https://eflow.empresa.com.mx/api-bin/eflow/folio

add

Agregar un nuevo folio en un proceso

Parámetros

  • proceso : Número proceso
  • station : Número de estación donde colocar el folio
  • label : opcional. Se se debe asignar esta etiqueta al folio para su posterior seguimiento, si se omite se asigna la etiqueta estándar : proceso-folio
  • obj : opcional, permite en la misma transacción llenar los datos del objeto asociado a este folio
{
    "cmd": "add",
    "process": 1,
    "station": 1,
    "obj": {
        "ff_campo1": "valor1",
        "ff_campo2": "valor2",
        ...
    },
}

cancel

Cancelar un folio existente

Parámetros

  • proceso : Número proceso (obligatorio)
  • station : Cancelar folio ubicado en esta estación (0 - todos , n - estación específica)
  • folio : Número de folio interno de eFlow
  • label : Opcional, si no se suministra folio, se deberá reportar la etiqueta del usuario
  • force : [0,1] Opcional, eliminar todos los paralelos (obligatorio si no se define station), eliminar aun si la estación no tiene autorizado cancelar
{
  "cmd": "cancel",
  "process": 1,
  "station": 0,
  "folio": 111,
  "force": 1
}

finish

Terminar folio en un proceso

Parámetros

  • proceso : Número proceso (obligatorio)
  • station : Número de estación donde se debe localizar el folio (obligatorio)
  • folio : Número de folio interno de eFlow (opcional recomendado)
  • label : Opcional, si no se suministra folio, se deberá reportar la etiqueta del usuario
{
  "cmd": "finish",
  "process": 1,
  "station": 1,
  "folio": 111
}

update

Actualizar datos del folio en un proceso

Parámetros

  • proceso : Número proceso (obligatorio)
  • folio : Número de folio interno de eFlow (obligatorio)
  • obj : Datos a actualizar (obligatorio)
    "cmd": "update",
    "process": 1,
    "folio": 1,
    "obj": {
        "ff_dato1": "valor1",
        "ff_dato2": "valor2",
        ...
    },

get

Obtener datos de registro de un folio en el sistema

curl -L --cookie "auth_tkt=Y...jQ3" "https://eflow.miempresa.com.mx/api-bin/eflow/folio?p=2&f=868"

{"status":false,"message":"No tiene permisos para ver la historia de este folio."}%

curl "https://eflow.empresa.com.mx/api-cgi/eflow/folio?p=2&f=868"
curl "https://eflow.empresa.com.mx/api-cgi/eflow/folio?f=2-868"
curl "https://eflow.empresa.com.mx/api-cgi/eflow/folio?p=2&lable=AAC-0003444-444"

Desarrollo APIs con perl

Si requiere desarrollar sus propias APIs eFlow ofrece una librería para facilitar la creación de APIs para perl.

Podrá encontrar una implementación básica en el directorio : /home/eflowweb/cgi/api/eflow/test/echo.pl

Eliminar echo.pl

Aun cuando la aplicación no transmite o entrega valores sensibles de eFlow, se recomienda eliminarla después de haberla estudiado, o por lo menos moverla a una zona no pública para evitar que se acceda a ella indiscriminadamente sobre internet.

O por lo menos editarla y asignar un secreto fuerte para que la pueda utilizar mientras la estudia

JApi.pm

new : Crear objeto

$api = CGI::JApi->new({
    expire => 0,
    secret => 'secreto',
    url => ['https://sitio1.com.mx','https://sitio2.com.mx'],
    DELETE => \&del,
    GET => \&get,
    PUT => \&put,
    POST => \&post,
    pretty => 1,
});

Parámetros

  • secret : Si su API, está localizada en la sección pública, se recomienda asignar un valor secreto a compartir entre su aplicación de consumo y su api. Al llamar la API, si esta opción fue configurada, la librería revisará que se haya enviado el secreto correctamente en la transacción, si no es así se negará el acceso al resto de su programa. (opcional)
  • El secreto se debe enviar como cookie o en el encabezado del request
  • Encabezado o cookie : japiauth: secreto
  • Si está implementando una api pública no deberá escribir ningún secreto
  • expire : 0 No expirar, numero de segundos para expirar el ticket entregado
  • url : Si está realizando llamadas cruzadas entre dominios, deberá definir que dominios tienen autorizado acceder a esta API, si no declara ningún arreglo, se permite el acceso libre. (opcional)
  • DELETE, GET, PUT, POST : Apuntadores a las rutinas que van a manejar la llamada del método correspondiente. Si no declara una rutina para manejar el acceso, se generará un error de que esa opción no está soportada. Debe por lo menos existir un apuntador que resuelva la llamada
  • pretty : Si se debe de formatear e indentar el json de respuesta. Es útil únicamente cuando estamos en desarrollo y usamos utilerías como curl para hacer pruebas, permite hace más legible la respuesta json en una terminal

Acciones realizadas al crear objeto

  • Librearía lee datos de llamada
  • Si el request es OPTIONS, valida URLs válidas y regresa mensajes de autorización o rechazo de acceso
  • Si existe secreto, validar que secreto sea igual en la llamada
  • Definir tipo de llamada : PUT, GET, POST, DELETE.
  • Leer parámetros e ingresarlos en : $$api{data}{llave}
  • Si se recibe un objeto json se accede a los elementos usando : $$api{data}{llave}{..}{..}
  • Si todo está bien regresar objeto construido

Respuestas

Todas las respuestas generadas por la librería tienen el formato.

{
    "status": [true,false],
    "message": "Mensage al usuario, error o exitoso",
    "data" : objeto,
}

Métodos Generales

Método Parámetros Uso Ejemplo
MessageSuccess string Enviar mensaje respuesta con estatus = true $api->MessageSuccess("Todo salió bien")
MessageError string Enviar mensaje respuesta con estatus = false $api->MessageSuccess("Error al acceder a información")
MessageData string,objeto Enviar mensaje respuesta con estatus = true $api->MessageData("registro",$ref_datos)
ProcessRequest ninguno Procesar llamada POST,GET,... $api->ProcessRequest()
me ninguno Regresar valores del usuario si está registrado $me = $api->me()

Ejemplo echo

Esta pequeña aplicación colocada en la parte pública de eFlow, solo regresa como respuesta lo que se le envía.

Ejemplos curl, usando Encabezado y Cookie para enviar el secreto

# Secreto en encabezado

curl -H "japiauth: secreto" \
-X POST https://eflow.empresa.com.mx/cgi/api/test/echo.pl \
-H 'Content-Type: application/json' \
-d '{"num":123456,"cliente":"municipio","donde":"1"}'

# Secreto en cookie

curl --cookie "japiauth=secreto" \
-X PUT https://eflow.empresa.com.mx/cgi/api/test/echo.pl \
-H 'Content-Type: application/json' \
-d '{"num":123456,"cliente":"municipio","donde":"1"}'

# Respuesta

{"message":"Echo datos recibidos en data","status":true,"data":{"cliente":"municipio","num":123456,"donde":"1"}

# Ejemplos , GET, DELETE, OPTIONS
curl -v -H "japiauth: secreto" \
-X GET "https://eflow.miempresa.com/cgi/api/test/echo.pl?id=33"

curl -v -H "japiauth: secreto" \
-X GET "http://eflow.miempresa.com/cgi/api/test/echo.pl"

curl -v -H "japiauth: secreto" \
-X DELETE "https://eflow.miempresa.com/cgi/api/test/echo.pl?id=99"

curl -v -H "Origin: eflow.com.mx" \
-X OPTIONS "https://eflow.miempresa.com/cgi/api/test/echo.pl"

echo.pl

#!/usr/bin/perl

use Eflow::JApi;
use utf8;

our ($api);

$api = CGI::JApi->new({
    secret => 'mi secreto',
    # url => ['https://sitio1.com.mx','https://sitio2.com.mx'],
    DELETE => \&del,
    GET => \&get,
    PUT => \&put,
    POST => \&post,
});

$api->ProcessRequest();

sub del {
    my $id = int($api->param('id'));
    $api->MessageSuccess("registro eliminado $id");
}

sub get {
    $api->MessageSuccess("registro obtenido $$api{data}{id}");
}

sub post {
    if ($$api{data}) {
        $api->MessageData('Echo datos recibidos en un arreglo',[$$api{data}]);
    } else {
        $api->MessageError('No se recibieron datos a procesar, áéíóúñÑ¡');
    }
}

sub put {
    if ($api->{data}) {
        $api->MessageData('Echo datos recibidos en data',$api->{data});
    } else {
        $api->MessageSuccess('No se recibieron datos a procesar, áéíóúñÑ¡');
    }
}