Unofficial Content

Objetivo:

Facilitar y centralizar el acceso y modificacion de los datos de una entidad. 

Uso

Dada una Entidad (en forma de transaccion) facilitar el acceso a sus datos con operaciones comunes. 

Ejemplo

Dada la transaccion Customer

Customer
*CustomerId
CustomerName  //tiene indice unico por CustomerName
CustomerAddress
CustomerType

se pueden poner dicha transaccion como BC y generar los objetos para lograr:

//CONSULTAS (QUERIES)

  • &CustomerCollection = GetAll()   // Se implementa con un Customer_DP - Data provider 
  • &CustomerCollection = GetBy<Condition>(&ConditionParameters)  // Se implementa con un Customer_DP<Condition> - DataProvider que usa un Data Selector por <Condition>
    • Customer_DS_Condition(&ConditionParameters) // Data Selector por Condition , &ConditionParameters es un SDT con los parametros de la condicion
  • &CustomerCollection = GetByType(&CustomerType)   // Se implementa con un DP que filtra por Type
  • &Customer = GetByKey(&CustomerId)  // Se implementa con el BC de Customer
  • &Customer = GetByName(&CustomerName) // Se implementa con un Data Provider que filtra por nombre
  • &CustomerType = GetType(&CustomerId) // Procedure que hace un for each por &CustomerID y devuelve el CustomerType. 

//MODIFICACIONES (MUTATIONS)

  • CustomerInsert(&Customer,&Messages)  // Se implementa con un Procedure que usa el BC para hacer insert
  • CustomerDelete(&Customer,&Messages) //igual que el anterior
  • CustomerUpdate(&Customer,&Messages) //Igual que el anterior
  • CustomerSetType(&CustomerID, &CustomerType, &Messages)  //BC que hace un Get con &CustomerID, actualiza el &CustomerType y hace el Update
  • CustomerSetName(&CustomerID, &CustomerName,&Messages) // igual que el anterior. 

Tambien generara el objeto API que engloba todo el acceso. 

Customer{

//Queries - Only Read Data
[RestVerb(GET)]
GetAll(out:&CustomerCollection) => CustomerGetAll(0, 99999999, &CustomerCollection);
GetAll_Paginated(in:&PageNumber, in:&PageSize, out:&CustomerCollection) => CustomerGetAll(&PageNumber, &PageSize, out:&CustomerCollection);
GetByKey(in:&CustomerId,out:&Customer) => CustomerGetByKey(&CustomerId,&Customer) ;
GetCustomerType(in:&CustomerId,out:&CustomerType) => CustomerGetType(&CustomerId,&CustomerType); 
Exist(in:&CustomerId,out:&CustomerExist) => CustomerExist(&CustomerId,&CustomerExist); 

//Mutations - Change Data
[RestVerb(POST) ]
Insert(in:&Customer, out:&Messages) => CustomerInsert(&Customer,&Messages) ;
[RestVerb(DELETE), RestPath /Customer/&CustomerID]
Delete(in:&CustomerID,out:&Messages) => CustomerDelete(&CustomerID, &Messages);
[RestVerb(PUT)] 
Update(in:&Customer,out:&Messages) => CustomerUpdate(&Customer, &Messages);
[RestVerb(PUT)]
SetCustomerType(in:&CustomerID, in:&CustomerType) => CustomerSetType(&CustomerId,&CustomerType);
}

Lista de Objetos que se necesitan

  • &Customer - Variable basada en BC Customer
  • &CustomerCollection - Collection de &Customer
  • &CustomerID - Basada en CustomerID - Puede ser &CustomerKEY SDT en caso de ser una clave compuesta, para tener menos parametros. 
  • CustomerDPGetAll - Data Provider que devuelve todos los Customers 
  • CustomerDPGetByKey - Data Provider que devuelve un Customer por clave
  • CustomerDPGetBy<Condition>(&Customer<Condition>Filters) - Data Provider que devuelve collection de Customers, dada una condicion
  • CustomerDS<Condition>(&Customer<Condition>Filters) - Data Selector que filtra por la condicion especificada. 
  • &Customer<Condition>Filters - SDT que tiene la lista de parametros de DS correspondiente a <Condition>
  • CustomerGetType - Procedure que recibe una KEY devuelve el Att CustomerType // De estos pueden haber varios para cada uno de los atributos secundarios que se necesiten.
  • CustomerInsert, CustomerUpdate, CustomerDelete - son procedures que usan los BC para hacer el ABM de la tabla Customer
  • CustomerSet<Att> - Procedure que recibe una KEY y el valor de un ATT y lo asigna usando el BC.  // Habra varios de estos. 

Ademas de todos estos, se generaran (opcionalemente) los objetos que faciliten el acceso remoto a la API desde la misma KB. 

CustomerRemoteInsert  //Llama a traves de REST a CustomerInsert

CustomerRemoteDelete  //

Esto puede hacerse para todos los servicios publicados en la API. 

 

Acceso local (desde la KB, a la entidad, en forma local)

//Usa internal como protocolo
&CustomerCollection = CustomerAPI.GetAll()

Lo ideal, seria poder escribir siempre el mismo codigo y por configuracion, poder decirle si es remoto o local 

//Para poder llamar remoto (ESTO ES SOLO UNA SUGERENCIA)
[Protocol=REST, host='remotehost', baseurl='\remotebaseurl']
&CustomerCollection = CustomerAPI.GetAll()

//Para llamar al objeto local
[Protocol =INTERNAL]
&CustomerCollection = CustomerAPI.GetAll()

 

Cosas que faltan (definir)

Codigo de Retorno

Que deben devolver ? Alcanza con &RestCode ? Si se usa otro protocolo en el futuro, ese codigo de retorno va a alcanzar?

Estructura de Mensajes ? Debe depender del modulo GeneXus o ser independiente? 
Usar una SDT unico de retorno, que incluya mensajes (id y message) y codigo de retorno?

Como probar el objeto API ? (ESTA ES IMPORTANTE)

Hay que definir bien como se puede testear en forma unitaria los objetos API y aseguarse que sean compatibles y no se rompa la compatiblidad sobre todo de los objetos API que sean publicados para ser consumidos desde fuera de la aplicacion. 

Como hacer el Deploy de los objetos API ?

Pensar en la necesidad de publicar en API Gateways y softwares parecidos. 

Clave  de la entidad.

Cuando la clave de la entidad es compuesta, uso un SDT con los atributos y paso como parametro el SDT o conviene usar variables basadas en atributos que la componen?

SDT tiene la ventaja que queda facil de definir, y la llamada queda con menos parametros y mas facil de leer. 
La desventaja es que al llamarlo, tengo que cargar el SDT

ATT tiene la ventaja que no debo cargar nada para llamar al objeto
La desventaja es ques la entidad tiene muchos atributos en la clave, es dificil de entender en los parametros posicionales. 

Versionado

El nro de version, se puede manejar (inicialmente y de forma simple) en la propiedad Service Base Path del objeto API
En una segunda version se podra definir diferente. 

Service Base Path = <API object name>/v1/

Log

Falta definir que nivel de log se va a llevar y que eventos/errores se van a registrar

Seguridad

Falta definir cómo se van a asegurar estos servicios. 
Una cosa importante es poder separar las API como internas (que solo puedan acceder desde dentro de la KB que las contienen) y externas (que puedan ser accedidas como servicios). 

Throttling (Control de ancho de banda y cantidad de invocaciones)

Control de no abuso de estos servicios. Poder establecer algunas reglas de control para determinar si alguien esta abusando o haciendo un DoS y no ejecutarlo. 

After / Before

Definir la mejor forma de programar los eventos After y Before de cada servicio y los globales. 

Paginado en los Get que devuelven Collection

En los data provider que devuelvan collection, agregar paginado. 
Luego podemos tener 2 metodos, uno con paginado y otro sin paginado, que utilicen al mismo data provider, para simplificar la programacion en caso que quiera traer todo. 

Agregacion 
Ver si se pueden generar en forma mas o menos facil, funciones de agregacion por un conjunto de atributos. 

Elegir los indicadores y una funcion de agregacion SUM, AVG, MIN, MAX, COUNT

Elegir por que dimensiones se quiere agrupar y devolver los registros totalizadores de eso. 

Entity Provider Instance Structure

Last update: February 2024 | © GeneXus. All rights reserved. GeneXus Powered by Globant