Fundamentos de ABAP RAP: RESTful ABAP Programming

Kategorie
ABAP-Statements
Veröffentlicht
Autor
Johannes

RAP (RESTful ABAP Programming) es el modelo de programación moderno para aplicaciones transaccionales en SAP. Forma la base para SAP Fiori Apps, servicios OData y desarrollo en la nube en SAP BTP.

Conceptos Fundamentales

  • Business Object (BO): Objeto de negocio con datos y comportamiento
  • CDS View: Modelo de datos (ver CDS Views)
  • Behavior Definition (BDEF): Declara el comportamiento (CRUD, Actions, Validations)
  • Behavior Implementation (BIL): Implementa el comportamiento en ABAP

Arquitectura RAP

┌─────────────────────────────────────────────┐
│ Fiori UI │
├─────────────────────────────────────────────┤
│ Servicio OData │
├─────────────────────────────────────────────┤
│ Capa de Projection (C_*) │
├─────────────────────────────────────────────┤
│ Capa Business Object (I_*) │
│ ┌─────────────┐ ┌────────────────────┐ │
│ │ CDS View │ │ Behavior │ │
│ │ (Datos) │ │ Definition (BDEF) │ │
│ └─────────────┘ └────────────────────┘ │
│ │ │
│ ┌───────────▼───────────┐ │
│ │ Behavior │ │
│ │ Implementation (BIL) │ │
│ └───────────────────────┘ │
├─────────────────────────────────────────────┤
│ Base de Datos │
└─────────────────────────────────────────────┘

Escenario Managed vs. Unmanaged

AspectoManagedUnmanaged
CRUDAutomático por el frameworkImplementar manualmente
TransaccionesControladas por frameworkControl propio
EsfuerzoBajoMayor
FlexibilidadOperaciones estándarControl total
Recomendado paraNuevos desarrollosIntegración legacy

Ejemplo: Escenario Managed

1. Tabla de Base de Datos

@EndUserText.label : 'Travel'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
define table ztravel {
key client : abap.clnt not null;
key travel_id : abap.numc(8) not null;
agency_id : abap.numc(6);
customer_id : abap.numc(6);
begin_date : abap.dats;
end_date : abap.dats;
total_price : abap.curr(16,2);
currency_code : abap.cuky;
description : abap.string(256);
status : abap.char(1);
created_by : abap.uname;
created_at : abap.utclong;
last_changed_by: abap.uname;
last_changed_at: abap.utclong;
}

2. Interface CDS View (I_*)

@AbapCatalog.sqlViewName: 'ZITRAVELV'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Travel - Interface View'
@Metadata.allowExtensions: true
define root view entity ZI_Travel
as select from ztravel
{
key travel_id as TravelId,
agency_id as AgencyId,
customer_id as CustomerId,
begin_date as BeginDate,
end_date as EndDate,
@Semantics.amount.currencyCode: 'CurrencyCode'
total_price as TotalPrice,
@Semantics.currencyCode: true
currency_code as CurrencyCode,
description as Description,
status as Status,
@Semantics.user.createdBy: true
created_by as CreatedBy,
@Semantics.systemDateTime.createdAt: true
created_at as CreatedAt,
@Semantics.user.lastChangedBy: true
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt
}

3. Behavior Definition (BDEF)

managed implementation in class zbp_i_travel unique;
strict ( 2 );
define behavior for ZI_Travel alias Travel
persistent table ztravel
lock master
authorization master ( instance )
etag master LastChangedAt
{
// Operaciones estándar
create;
update;
delete;
// Mapeo de campos para base de datos
field ( readonly ) TravelId;
field ( readonly ) CreatedBy, CreatedAt, LastChangedBy, LastChangedAt;
// Numeración automática
field ( numbering : managed ) TravelId;
// Actions
action ( features : instance ) acceptTravel result [1] $self;
action ( features : instance ) rejectTravel result [1] $self;
// Validations
validation validateDates on save { field BeginDate, EndDate; }
validation validateCustomer on save { field CustomerId; }
// Determinations
determination setStatusNew on modify { create; }
}

4. Behavior Implementation (BIL)

CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS:
get_instance_features FOR INSTANCE FEATURES
IMPORTING keys REQUEST requested_features FOR Travel
RESULT result,
acceptTravel FOR MODIFY
IMPORTING keys FOR ACTION Travel~acceptTravel
RESULT result,
rejectTravel FOR MODIFY
IMPORTING keys FOR ACTION Travel~rejectTravel
RESULT result,
validateDates FOR VALIDATE ON SAVE
IMPORTING keys FOR Travel~validateDates,
validateCustomer FOR VALIDATE ON SAVE
IMPORTING keys FOR Travel~validateCustomer,
setStatusNew FOR DETERMINE ON MODIFY
IMPORTING keys FOR Travel~setStatusNew.
ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD get_instance_features.
" Leer datos actuales
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel)
FAILED failed.
" Feature-Control basado en estado
result = VALUE #( FOR ls_travel IN lt_travel
( %tky = ls_travel-%tky
%features-%action-acceptTravel = COND #(
WHEN ls_travel-Status = 'O' THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
%features-%action-rejectTravel = COND #(
WHEN ls_travel-Status = 'O' THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
)
).
ENDMETHOD.
METHOD acceptTravel.
" Establecer estado a 'Accepted'
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
Status = 'A' ) )
FAILED failed
REPORTED reported.
" Devolver resultado
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT result.
ENDMETHOD.
METHOD rejectTravel.
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
Status = 'X' ) )
FAILED failed
REPORTED reported.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT result.
ENDMETHOD.
METHOD validateDates.
" Leer datos
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( BeginDate EndDate )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
LOOP AT lt_travel INTO DATA(ls_travel).
" La fecha de fin debe ser posterior al inicio
IF ls_travel-EndDate < ls_travel-BeginDate.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-EndDate = if_abap_behv=>mk-on
) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-EndDate = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'La fecha de fin debe ser posterior a la fecha de inicio'
)
) TO reported-travel.
ENDIF.
" El inicio no puede estar en el pasado
IF ls_travel-BeginDate < cl_abap_context_info=>get_system_date( ).
APPEND VALUE #(
%tky = ls_travel-%tky
%element-BeginDate = if_abap_behv=>mk-on
) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-BeginDate = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'La fecha de inicio no puede estar en el pasado'
)
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD validateCustomer.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( CustomerId )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
" Verificar clientes
LOOP AT lt_travel INTO DATA(ls_travel).
IF ls_travel-CustomerId IS INITIAL.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-CustomerId = if_abap_behv=>mk-on
) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-CustomerId = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'El cliente es obligatorio'
)
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD setStatusNew.
" Al crear, establecer estado en 'Open'
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status )
WITH VALUE #( FOR ls_travel IN lt_travel
WHERE ( Status IS INITIAL )
( %tky = ls_travel-%tky
Status = 'O' ) )
REPORTED reported.
ENDMETHOD.
ENDCLASS.

5. Projection View (C_*)

@EndUserText.label: 'Travel - Projection View'
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
@Search.searchable: true
define root view entity ZC_Travel
provider contract transactional_query
as projection on ZI_Travel
{
key TravelId,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
AgencyId,
@Search.defaultSearchElement: true
CustomerId,
BeginDate,
EndDate,
TotalPrice,
CurrencyCode,
@Search.defaultSearchElement: true
Description,
@ObjectModel.text.element: ['StatusText']
Status,
_StatusText.Text as StatusText : localized,
CreatedBy,
CreatedAt,
LastChangedBy,
LastChangedAt
}

6. Projection Behavior Definition

projection;
strict ( 2 );
define behavior for ZC_Travel alias Travel
{
use create;
use update;
use delete;
use action acceptTravel;
use action rejectTravel;
}

7. Service Definition

@EndUserText.label: 'Travel Service Definition'
define service ZUI_TRAVEL_O4 {
expose ZC_Travel as Travel;
}

8. Service Binding

- Nombre: ZUI_TRAVEL_O4
- Tipo de Binding: OData V4 - UI
- Service Definition: ZUI_TRAVEL_O4

EML - Entity Manipulation Language

" === READ ENTITIES ===
READ ENTITIES OF zi_travel
ENTITY Travel
FIELDS ( TravelId AgencyId Status )
WITH VALUE #( ( TravelId = '00000001' ) )
RESULT DATA(lt_travel)
FAILED DATA(failed)
REPORTED DATA(reported).
" === MODIFY ENTITIES - Create ===
MODIFY ENTITIES OF zi_travel
ENTITY Travel
CREATE FIELDS ( AgencyId CustomerId BeginDate EndDate )
WITH VALUE #( (
%cid = 'CID_1'
AgencyId = '000001'
CustomerId = '000010'
BeginDate = cl_abap_context_info=>get_system_date( )
EndDate = cl_abap_context_info=>get_system_date( ) + 7
) )
MAPPED DATA(mapped)
FAILED failed
REPORTED reported.
" === MODIFY ENTITIES - Update ===
MODIFY ENTITIES OF zi_travel
ENTITY Travel
UPDATE FIELDS ( Status Description )
WITH VALUE #( (
TravelId = '00000001'
Status = 'A'
Description = 'Actualizado'
) )
FAILED failed
REPORTED reported.
" === MODIFY ENTITIES - Delete ===
MODIFY ENTITIES OF zi_travel
ENTITY Travel
DELETE FROM VALUE #( ( TravelId = '00000001' ) )
FAILED failed
REPORTED reported.
" === MODIFY ENTITIES - Execute Action ===
MODIFY ENTITIES OF zi_travel
ENTITY Travel
EXECUTE acceptTravel FROM VALUE #( ( TravelId = '00000001' ) )
FAILED failed
REPORTED reported.
" === COMMIT ENTITIES ===
COMMIT ENTITIES
RESPONSE OF zi_travel
FAILED DATA(commit_failed)
REPORTED DATA(commit_reported).

Elementos de Behavior

Actions

" Action de instancia (sobre una fila)
action acceptTravel result [1] $self;
" Action estática (sin instancia)
static action createFromTemplate result [1] $self;
" Factory Action (crea nueva instancia)
factory action copyTravel [1];
" Con parámetros
action setStatus parameter ZA_StatusParameter result [1] $self;

Validations

" En Save
validation validateDates on save { field BeginDate, EndDate; }
" En Modify (verificación inmediata)
validation validatePrice on modify { field TotalPrice; }
" Validations de Draft
draft validation validateConsistency on save;

Determinations

" En Create
determination setDefaults on modify { create; }
" En cambio de campo
determination calculateTotal on modify { field Quantity, Price; }
" En Save
determination generateNumber on save { create; }

Feature Control

" Features globales
field ( readonly ) TravelId;
field ( mandatory ) CustomerId;
field ( readonly : update ) AgencyId;
" Features de instancia (dinámicos)
action ( features : instance ) acceptTravel;

Draft Handling

managed implementation in class zbp_i_travel unique;
strict ( 2 );
with draft;
define behavior for ZI_Travel alias Travel
persistent table ztravel
draft table zdraft_travel
lock master
total etag LastChangedAt
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
// Draft-Actions (disponibles automáticamente)
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft action Resume;
draft determine action Prepare;
}

Clases Importantes

ClaseDescripción
cl_abap_behavior_handlerClase base para Behavior Implementation
cl_abap_context_infoContexto del sistema (Fecha, Usuario)
if_abap_behvConstantes (fc-o-enabled, mk-on)
if_abap_behv_messageMessage-Severity

Notas Importantes / Mejores Prácticas

  • Escenario Managed para nuevos desarrollos - el framework gestiona CRUD.
  • Interface Views (I_*) para modelo de datos, Projection Views (C_*) para UI/API.
  • EML (Entity Manipulation Language) para acceso programático al BO.
  • Validations para reglas de negocio, Determinations para valores automáticos.
  • Actions para operaciones de negocio más allá de CRUD.
  • Feature Control para disponibilidad dinámica de campos/acciones.
  • Draft para almacenamiento intermedio en entradas complejas.
  • Usa IN LOCAL MODE para acceso sin verificación de autorización.
  • FAILED y REPORTED para manejo de errores y mensajes.
  • Strict Mode (strict ( 2 )) para validación de mejores prácticas.
  • Combina con CDS Views para el modelo de datos.