Hola a todos !
En este blog voy a hablar sobre el modelo RAP:Modelo de programación RESTful ABAP. Como lo describe SAP: –
El modelo de programación de aplicaciones ABAP RESTful (abreviado RAP) define la arquitectura para el desarrollo integral eficiente de servicios OData intrínsecamente optimizados para SAP HANA (como las aplicaciones Fiori). Admite el desarrollo de todo tipo de aplicaciones Fiori, así como la publicación de API web. Se basa en tecnologías y marcos como Core Data Services (CDS) para definir modelos de datos semánticamente ricos y una infraestructura de modelo de servicio para crear servicios OData con enlaces a un protocolo OData y servicios de aplicaciones basados en ABAP para lógica personalizada y usuario basado en SAPUI5. interfaces
Intentaremos entenderlo técnicamente mientras navegamos…
Estoy seguro de que muchos de ustedes habrán visto la siguiente imagen. Escaneémoslo una vez más.
La programación ABAP clásica es algo que hemos usado desde tiempos inmemoriales y aún vive hasta la fecha, pero con la tecnología cambiando cada pocos años, no había forma de que pudiéramos apegarnos al pasado.
Con la llegada de S/4HANA, la adopción de Fiori tuvo un gran impulso como la futura tecnología de interfaz de usuario (aunque estaba disponible antes del lanzamiento de S/4HANA 1511), al igual que la adopción del modelo de programación ABAP para SAP Fiori. Por lo tanto, muchos de ustedes conocerían esta arquitectura (cuadro central en la imagen de arriba) y la habrían utilizado en sus proyectos en los que habrían creado una vista CDS (básica, interfaz, Consumo, con elementos Fiori) y la habrían usado en un proyecto de puerta de enlace SEGW y consumió ese proyecto en una aplicación Fiori, etc.
Bueno, esto funciona bien, pero con un mayor cambio tecnológico hacia la nube, también es importante tener un modelo que pueda estar listo para la nube. Aquí es donde el modelo RAP está encontrando su lugar (junto con CAP, pero el consumo del modelo CAP está más impulsado por NodeJS/Java, mientras que RAP está dentro de los dominios de ABAP). El núcleo del modelado de datos para RAP sigue siendo CDS y el consumo se define mediante una Definición de comportamiento + Implementación de comportamiento + Definición de servicio + Enlace de servicio, como se muestra en la Imagen grande a continuación.
Dónde ¿Reside el servicio ABAP? SaaS en BTP
Cuales base de datos que utiliza: SAP HANA integrado
Cómo la codificación está hecha – Via Eclipse ADT
Qué tipo de lenguaje – ABAP en la Nube
No voy a dedicar más tiempo a estas imágenes, ya que me siento como un ABAPer, es mejor comprender los conceptos a través del código y no de diapositivas. Entonces, comencemos con nuestro modelo de datos de empleados para el cual queremos realizar operaciones CRUD en un empleado.
Como primer paso, obtenga acceso a la cuenta de prueba BTP o cualquier cuenta BTP donde pueda acceder a «Preparar una cuenta para la prueba ABAP»
Haga clic en Boosters ->Preparar una cuenta para prueba ABAP ->Iniciar
Una vez hecho esto, obtendrá una clave de servicio que debe descargar y conservar.
Puede descargar la última versión de Eclipse desde https://www.eclipse.org/downloads/packages/
Y una vez hecho esto, cree un proyecto en la nube ABAP
Puede ingresar su clave de servicio aquí
Crea un Paquete para tus desarrollos
Una vez que se crea el paquete, cree una nueva tabla para Empleado
Llamémoslo ZTEST_EMPL
La estructura parece
@EndUserText.label : 'Employee Table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table ztest_empl {
key mandt : abap.clnt not null;
key id_int : sysuuid_x16 not null;
id_ext : abap.char(10) not null;
firstname : abap.char(20);
lastname : abap.char(20);
@Semantics.amount.currencyCode : 'ztest_empl.currency'
salary : abap.curr(10,2);
currency : abap.cuky;
exp : abap.int1;
role : abap.char(50);
active : abap_boolean;
created_by : syuname;
created_at : timestampl;
last_changed_by : syuname;
last_changed_at : timestampl;
}
El elemento de datos de id_int es importante porque permite la generación automática de id_int.
Como el núcleo de las tecnologías RAP es una vista CDS, creemos una en la parte superior de nuestra mesa
@EndUserText.label: 'Interface view for Employee'
define root view entity ZI_test_empl
as select from ztest_empl
{
key id_int,
id_ext,
firstname,
lastname,
salary,
currency,
exp,
role,
active,
@Semantics.user.createdBy: true
created_by,
@Semantics.systemDateTime.createdAt: true
created_at,
@Semantics.user.lastChangedBy: true
last_changed_by,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at
}
Tenga en cuenta que es una entidad de vista, por lo tanto, no tiene una anotación de vista SQL.
Ahora crearé una vista de consumo raíz.
@EndUserText.label: 'Consumption View'
@Search.searchable: true
@Metadata.allowExtensions: true
define root view entity ZC_TEST_EMPL
as select from ZI_test_empl as Empl
{
key id_int,
id_ext,
firstname,
lastname,
salary,
currency,
exp,
role,
active,
@Semantics.user.createdBy: true
created_by,
@Semantics.systemDateTime.createdAt: true
created_at,
@Semantics.user.lastChangedBy: true
last_changed_by,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at
}
Descargo de responsabilidad:
Tenga en cuenta que no he creado una vista de Proyección, aunque la imagen en la sección Evolución sugiere crear una vista de proyecto. Estoy tratando de ver si podría trabajar sin él técnicamente. Puede crear una vista de Proyección y exponer lo que sea necesario para exponer en la definición de comportamiento correspondiente. Mi comportamiento La implementación está directamente en la vista Consumo y no en la vista de interfaz. Aunque la vista de proyección brindaría ventajas en términos de lo que quiera proyectar, estoy tratando de ver si hay una limitación técnica si no sigo ese camino.
Cree una extensión de metadatos en la vista Consumo para poder segregar las anotaciones Fiori.
@Metadata.layer: #CORE
@UI: {
headerInfo: { typeName: 'Employee',
typeNamePlural: 'Employees',
title: { type: #STANDARD, label: 'Employee', value: 'id_ext' } },
presentationVariant: [{ sortOrder: [{ by: 'firstname', direction: #ASC }] }] }
annotate view ZC_TEST_EMPL with
{
@UI.facet: [ { id: 'Employee',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Employee',
position: 10 } ]
@UI.hidden: true
id_int;
@UI: {
lineItem: [ { position: 10, importance: #HIGH } ],
identification: [ { position: 10, label: 'ID [1,...,99999999]' } ] }
@EndUserText.label: 'Employee Id'
id_ext;
@UI: {
lineItem: [ { position: 20, importance: #HIGH } ],
identification: [ { position: 20, label: 'First Name' } ],
selectionField: [{ position : 10 }]}
@EndUserText.label: 'First name'
@Search.defaultSearchElement: true
firstname;
@UI: {
lineItem: [ { position: 30, importance: #HIGH } ],
identification: [ { position: 30, label: 'Last Name' } ] }
@EndUserText.label: 'Last Name'
lastname;
@UI: {
lineItem: [ { position: 40, importance: #HIGH } ],
identification: [ { position: 40, label: 'Salary' } ] }
@EndUserText.label: 'Salary'
salary;
@UI: {
lineItem: [ { position: 50, importance: #HIGH } ],
identification: [ { position: 50, label: 'Currency' } ] }
currency;
@UI: {
lineItem: [ { position: 60, importance: #HIGH } ],
identification: [ { position: 60, label: 'Experience' } ] }
@EndUserText.label: 'Experience'
exp;
@UI: {
lineItem: [ { position: 70, importance: #HIGH } ],
identification: [ { position: 70, label: 'Role' } ] }
@EndUserText.label: 'Role'
role;
@UI: {
lineItem: [ { position: 80 }, { type: #FOR_ACTION, dataAction: 'setActive', label: 'Set Active' } ],
identification: [ { position: 80 }, { type: #FOR_ACTION, dataAction: 'setActive', label: 'Set Active' } ] }
@EndUserText.label: 'Active ?'
active;
@UI.hidden: true
created_by;
@UI.hidden: true
created_at;
@UI.hidden: true
last_changed_by;
@UI.hidden: true
last_changed_at;
}
Tenga en cuenta que el método asociado con dataAction = ‘setActive’ se usaría en Definición e implementación de comportamiento.
Esta es una lista de todos los comportamientos, básicamente significa cómo se comportaría mi entidad.
managed implementation in class zbp_c_test_empl unique;
define behavior for ZC_TEST_EMPL alias Empl
persistent table ZTEST_EMPL
lock master
//authorization master ( instance )
//etag master <field_name>
{
// CUD operations come by default
create;
update;
delete;
// manage numburing, read only and mandatory behaviours of the entity
field ( numbering : managed, readonly ) id_int;
field ( readonly ) active, salary, currency;
field ( readonly ) created_by, created_at, last_changed_by, last_changed_at;
field ( mandatory ) firstname, lastname;
// Function import to set the Employee to active/inactive
action ( features : instance ) setActive result [1] $self;
//determination of Salary based on Experience and Role
determination calcSalary on save { field exp, role; }
//validate various fields user is going to enter on the UI
validation validateFirstName on save { field firstname; }
}
Veamos esto uno por uno
La definición debe implementarse en una clase usando lógica personalizada usando EML (lenguaje de manipulación de entidades)
MÉTODO setActive.: este método establece el indicador activo en X cuando se pulsa el botón de la interfaz de usuario. El botón de la interfaz de usuario se establece en la extensión de metadatos y se vincula a este método.
MODIFY ENTITIES OF zc_test_empl IN LOCAL MODE
ENTITY Empl
UPDATE FIELDS ( active )
WITH VALUE #(
FOR wa IN keys ( %tky = wa-%tky
active = abap_true ) )
FAILED failed
REPORTED reported.
" Fill the response table
READ ENTITIES OF zc_test_empl IN LOCAL MODE
ENTITY Empl
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_empl).
result = VALUE #( FOR wa_empl IN lt_empl
( %tky = wa_empl-%tky
%param = wa_empl ) ).
ENDMETHOD.
¿Que hace?
MÉTODO calcSalary.
METHOD calcSalary.
READ ENTITIES OF zc_test_empl IN LOCAL MODE
ENTITY Empl
FIELDS ( exp role ) WITH CORRESPONDING #( keys )
RESULT DATA(lt_empl).
LOOP AT lt_empl ASSIGNING FIELD-SYMBOL(<fs_empl>).
IF <fs_empl>-role="Director" AND
<fs_empl>-exp >= '20'.
<fs_empl>-salary = '50000000'.
<fs_empl>-currency = 'INR'.
ELSEIF <fs_empl>-role="Director" AND
<fs_empl>-exp < '20'.
<fs_empl>-salary = '45000000'.
<fs_empl>-currency = 'INR'.
ELSE.
<fs_empl>-salary = '2000000'.
<fs_empl>-currency = 'INR'.
ENDIF.
MODIFY ENTITIES OF zc_test_empl IN LOCAL MODE
ENTITY Empl
UPDATE FIELDS ( salary currency )
WITH VALUE #(
( %tky = <fs_empl>-%tky
salary = <fs_empl>-salary
currency = <fs_empl>-currency ) ).
ENDLOOP.
ENDMETHOD.
¿Que hace?
MÉTODO validarNombre.
METHOD validateFirstName.
READ ENTITIES OF zc_test_empl IN LOCAL MODE
ENTITY Empl
FIELDS ( firstname ) WITH CORRESPONDING #( keys )
RESULT DATA(lt_empl).
READ TABLE lt_empl ASSIGNING FIELD-SYMBOL(<fs_empl>) INDEX 1.
CHECK sy-subrc EQ 0.
IF <fs_empl>-firstname CA '0123456789'.
APPEND VALUE #( %tky = <fs_empl>-%tky ) TO failed-empl.
APPEND VALUE #( %tky = <fs_empl>-%tky
%msg = new_message( id = 'ZEMPL_MSG'
number="000"
v1 = <fs_empl>-firstname
severity = if_abap_behv_message=>severity-error ) )
TO reported-Empl.
ENDIF.
ENDMETHOD.
¿Que hace?
Haga clic con el botón derecho en la vista de consumo y cree la definición del servicio
Exponer la vista Consumo como un servicio
Haga clic derecho en Definición de servicio y cree Enlace de servicio
Cuando haga clic en vista previa en el paso anterior, verá la siguiente pantalla.
Ahora haga clic en Crear botón. Aquí puede ingresar ID, Nombre, Apellido, Experiencia y Rol.
El salario se calculará en función de la experiencia y el rol. El indicador activo se puede configurar una vez que todo esté bien.
Ingrese los valores y presione Crear
Aparece la siguiente pantalla.
Ahora haga clic en Atrás y es posible que vea que el registro está lleno.
Puede seleccionar el registro y usar el botón Establecer activo para activarlo. Una vez hecho esto, la pantalla se ve a continuación
A medida que el mundo avanza hacia la nube, las tecnologías como RAP solo pueden fortalecerse cada vez más con una perspectiva positiva hacia una mayor adopción en los próximos años.
¡Feliz ABAP!
Calle Eloy Gonzalo, 27
Madrid, Madrid.
Código Postal 28010
Paseo de la Reforma 26
Colonia Juárez, Cuauhtémoc
Ciudad de México 06600
Real Cariari
Autopista General Cañas,
San José, SJ 40104
Av. Jorge Basadre 349
San Isidro
Lima, LIM 15073