ABAP RESTful Application Programming Model (RAP)
El modelo de SAP para crear aplicaciones Fiori y APIs OData con ABAP. Defines datos, comportamiento y servicio; el framework hace el resto.
- Apartados
- 12
- Revisado
- Octubre de 2026
- Fuentes
- 2 enlaces
Qué es RAP
RAP sustituye a los antiguos modelos de programación (BOPF, SEGW y Gateway clásico). Un objeto de negocio RAP se construye en capas, de la tabla a la aplicación:
Tu primera app RAP en 5 minutos
ADT trae un generador que crea todas las capas a partir de una tabla. Es la forma más rápida de empezar y de ver cómo encajan las piezas. Funciona en Eclipse y en VS Code, con BTP ABAP environment, S/4HANA Cloud o S/4HANA 2022 y posteriores.
@EndUserText.label : 'Viajes'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zviaje {
key client : abap.clnt not null;
key viaje_id : abap.numc(8) not null;
cliente_id : abap.char(10);
fecha_inicio : abap.dats;
@Semantics.amount.currencyCode : 'zviaje.moneda'
importe : abap.curr(15,2);
moneda : abap.cuky;
estado : abap.char(1);
cambiado_en : abp_lastchange_tstmpl;
}- Crea un paquete (en BTP, dentro de
ZLOCALsi es solo para practicar) y dentro la tablaZVIAJEcon el código de arriba. Actívala conCtrl+F3. - Pulsa con el botón derecho sobre la tabla y elige Generate ABAP Repository Objects…
- Selecciona el generador OData UI Service (en algunas versiones, ABAP RESTful Application Programming Model: UI Service).
- Revisa los nombres que propone: vistas
ZR_yZC_, behavior definitions, claseZBP_, service definition y binding. Pulsa Next y Finish. - Abre el service binding generado, pulsa Publish, elige la entidad y pulsa Preview. Ya tienes una app Fiori elements con lista, detalle, creación y borrado.
El generador crea la app con borradores (draft) y numeración automática. Lee el código que genera: es el mejor ejemplo de cómo se escribe un RAP completo.
1. El modelo de datos
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Viaje'
define root view entity ZR_Viaje
as select from zviaje
{
key viaje_id as ViajeId,
cliente_id as ClienteId,
fecha_inicio as FechaInicio,
@Semantics.amount.currencyCode: 'Moneda'
importe as Importe,
moneda as Moneda,
estado as Estado,
@Semantics.systemDateTime.lastChangedAt: true
cambiado_en as CambiadoEn
}2. El comportamiento
La behavior definition dice qué se puede hacer con el objeto: crear, modificar, borrar, acciones y validaciones. En el escenario managed, RAP guarda los datos por ti.
managed implementation in class zbp_r_viaje unique;
strict ( 2 );
define behavior for ZR_Viaje alias Viaje
persistent table zviaje
lock master
authorization master ( instance )
etag master CambiadoEn
{
create;
update;
delete;
field ( readonly : update ) ViajeId;
action aceptar result [1] $self;
validation validarFechas on save { create; field FechaInicio; }
mapping for zviaje
{
ViajeId = viaje_id;
ClienteId = cliente_id;
FechaInicio = fecha_inicio;
Importe = importe;
Moneda = moneda;
Estado = estado;
CambiadoEn = cambiado_en;
}
}La acción se programa en la clase de comportamiento con EML:
METHOD aceptar.
MODIFY ENTITIES OF zr_viaje IN LOCAL MODE
ENTITY Viaje
UPDATE FIELDS ( Estado )
WITH VALUE #( FOR ls_key IN keys
( %tky = ls_key-%tky Estado = 'A' ) ).
READ ENTITIES OF zr_viaje IN LOCAL MODE
ENTITY Viaje ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_viajes).
result = VALUE #( FOR ls_v IN lt_viajes
( %tky = ls_v-%tky %param = ls_v ) ).
ENDMETHOD.3. El servicio
@Metadata.allowExtensions: true
@EndUserText.label: 'Viaje (proyección)'
define root view entity ZC_Viaje
provider contract transactional_query
as projection on ZR_Viaje
{
key ViajeId,
ClienteId,
FechaInicio,
Importe,
Moneda,
Estado,
CambiadoEn
}@EndUserText.label: 'Servicio de viajes'
define service ZUI_VIAJE {
expose ZC_Viaje as Viaje;
}- Crea también la proyección del comportamiento (
projection;conuse create; use update; use delete; use action aceptar;). - Crea un service binding de tipo OData V4 - UI sobre
ZUI_VIAJE. - Pulsa Publish y después Preview: verás la app Fiori elements funcionando.
Usar el objeto desde ABAP con EML
EML (Entity Manipulation Language) lee y modifica objetos RAP desde cualquier programa respetando sus validaciones y bloqueos.
READ ENTITIES OF zr_viaje
ENTITY Viaje
FIELDS ( Estado Importe ) WITH VALUE #( ( ViajeId = '00000001' ) )
RESULT DATA(lt_viajes).
MODIFY ENTITIES OF zr_viaje
ENTITY Viaje
UPDATE FIELDS ( Estado )
WITH VALUE #( ( ViajeId = '00000001' Estado = 'A' ) )
FAILED DATA(ls_failed)
REPORTED DATA(ls_reported).
COMMIT ENTITIES.Managed, unmanaged y borradores
| Escenario | Quién guarda los datos | Cuándo usarlo |
|---|---|---|
| Managed | RAP | Aplicaciones nuevas: la opción por defecto |
| Managed con guardado propio | RAP, salvo el guardado final | Cuando hay que grabar con una BAPI o API existente |
| Unmanaged | Tu código | Reutilizar lógica antigua que ya hace todo |
| Con borrador (draft) | RAP guarda versiones intermedias | Formularios largos que el usuario completa en varias veces |
Qué pasa al guardar: interacción y guardado
Una transacción RAP tiene dos fases. En la fase de interacción el usuario o el programa modifica los datos en un búfer en memoria. Al hacer COMMIT ENTITIES empieza la secuencia de guardado: se completan y validan los datos y, si todo está bien, se graban en la base de datos.
En la secuencia de guardado no se puede llamar a COMMIT WORK ni a ROLLBACK WORK: de eso se encarga RAP.
Determinaciones y validaciones
Una determinación rellena o calcula datos automáticamente. Una validación comprueba los datos antes de guardarlos y, si algo falla, devuelve un mensaje. Se declaran en la behavior definition:
determination fijarEstado on modify { create; }
validation validarFechas on save { create; field FechaInicio; }Esta determinación pone el estado «O» (abierto) a los viajes nuevos que no tienen estado:
METHOD fijarEstado.
READ ENTITIES OF zr_viaje IN LOCAL MODE
ENTITY Viaje FIELDS ( Estado ) WITH CORRESPONDING #( keys )
RESULT DATA(lt_viajes).
DELETE lt_viajes WHERE Estado IS NOT INITIAL.
CHECK lt_viajes IS NOT INITIAL.
MODIFY ENTITIES OF zr_viaje IN LOCAL MODE
ENTITY Viaje UPDATE FIELDS ( Estado )
WITH VALUE #( FOR ls_v IN lt_viajes
( %tky = ls_v-%tky Estado = 'O' ) ).
ENDMETHOD.Y esta validación rechaza viajes con fecha de inicio pasada. failed indica qué registros fallan y reported lleva el mensaje, asociado al campo para que Fiori lo marque en rojo:
METHOD validarFechas.
READ ENTITIES OF zr_viaje IN LOCAL MODE
ENTITY Viaje FIELDS ( FechaInicio ) WITH CORRESPONDING #( keys )
RESULT DATA(lt_viajes).
DATA(lv_hoy) = cl_abap_context_info=>get_system_date( ).
LOOP AT lt_viajes INTO DATA(ls_viaje) WHERE FechaInicio < lv_hoy.
APPEND VALUE #( %tky = ls_viaje-%tky ) TO failed-viaje.
APPEND VALUE #( %tky = ls_viaje-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'La fecha de inicio no puede ser pasada' )
%element-FechaInicio = if_abap_behv=>mk-on )
TO reported-viaje.
ENDLOOP.
ENDMETHOD.Activar o desactivar acciones según los datos
Con el control de funciones (feature control) decides en cada registro qué botones y campos están disponibles. Por ejemplo, que no se pueda aceptar un viaje ya aceptado:
action ( features : instance ) aceptar result [1] $self;METHOD get_instance_features.
READ ENTITIES OF zr_viaje IN LOCAL MODE
ENTITY Viaje FIELDS ( Estado ) WITH CORRESPONDING #( keys )
RESULT DATA(lt_viajes).
result = VALUE #( FOR ls_v IN lt_viajes
( %tky = ls_v-%tky
%action-aceptar = COND #( WHEN ls_v-Estado = 'A'
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled ) ) ).
ENDMETHOD.Fiori elements lee este resultado y desactiva el botón Aceptar en los viajes que ya lo están, sin tocar la interfaz.
Borradores (draft)
Con borradores, lo que el usuario va escribiendo se guarda en una tabla aparte. Puede cerrar el navegador y seguir más tarde, y otro usuario no puede editar el mismo registro a la vez. Basta con declararlo:
managed implementation in class zbp_r_viaje unique;
strict ( 2 );
with draft;
define behavior for ZR_Viaje alias Viaje
persistent table zviaje
draft table zviaje_d
lock master total etag CambiadoEn
authorization master ( instance )
etag master CambiadoEn
{
create;
update;
delete;
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft action Resume;
draft determine action Prepare { validation validarFechas; }
}- ADT crea la tabla de borradores
ZVIAJE_Dcon un asistente rápido (Ctrl+1sobre el nombre). Prepareejecuta las validaciones antes de activar, para avisar al usuario antes de guardar.- Fiori elements muestra solo los botones Editar, Guardar y Descartar borrador.
Eventos de negocio
Un objeto RAP puede publicar eventos para que otros sistemas reaccionen, por ejemplo una app en BTP que envía un correo cuando se acepta un viaje. El evento se declara en la behavior definition y se lanza durante el guardado.
event viajeAceptado;" En el método save_modified de la clase de guardado (managed with additional save)
RAISE ENTITY EVENT zr_viaje~viajeAceptado
FROM VALUE #( FOR ls_v IN update-viaje WHERE ( Estado = 'A' )
( ViajeId = ls_v-ViajeId ) ).Para que el evento salga del sistema hay que configurar un event binding y un canal hacia SAP Event Mesh o Advanced Event Mesh.