Fondamentaux RAP ABAP : RESTful ABAP Programming

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

RAP (RESTful ABAP Programming) est le modèle de programmation moderne pour les applications transactionnelles dans SAP. Il constitue la base des applications SAP Fiori, des services OData et du développement Cloud sur SAP BTP.

Concepts fondamentaux

  • Business Object (BO) : Objet métier avec données et comportement
  • CDS View : Modèle de données (voir CDS Views)
  • Behavior Definition (BDEF) : Déclare le comportement (CRUD, Actions, Validations)
  • Behavior Implementation (BIL) : Implémente le comportement en ABAP

Architecture RAP

┌─────────────────────────────────────────────┐
│ Fiori UI │
├─────────────────────────────────────────────┤
│ OData Service │
├─────────────────────────────────────────────┤
│ Projection Layer (C_*) │
├─────────────────────────────────────────────┤
│ Business Object Layer (I_*) │
│ ┌─────────────┐ ┌────────────────────┐ │
│ │ CDS View │ │ Behavior │ │
│ │ (Daten) │ │ Definition (BDEF) │ │
│ └─────────────┘ └────────────────────┘ │
│ │ │
│ ┌───────────▼───────────┐ │
│ │ Behavior │ │
│ │ Implementation (BIL) │ │
│ └───────────────────────┘ │
├─────────────────────────────────────────────┤
│ Datenbank │
└─────────────────────────────────────────────┘

Managed vs. Unmanaged Szenario

AspectManagedUnmanaged
CRUDAutomatique par le frameworkImplémentation manuelle
TransactionsContrôlé par le frameworkContrôle propre
EffortFaiblePlus élevé
FlexibilitéOpérations standardContrôle total
Recommandé pourNouveaux développementsIntégration legacy

Exemple : Scénario Managed

1. Table de base de données

@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
{
// Opérations standard
create;
update;
delete;
// Mapping de champs pour la base de données
field ( readonly ) TravelId;
field ( readonly ) CreatedBy, CreatedAt, LastChangedBy, LastChangedAt;
// Numérotation automatique
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.
" Lire les données actuelles
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel)
FAILED failed.
" Feature-Control basé sur le statut
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.
" Définir le statut sur '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.
" Retourner le résultat
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.
" Lire les données
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 date de fin doit être après le début
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 date de fin doit être après la date de début"
)
) TO reported-travel.
ENDIF.
" Le début ne doit pas être dans le passé
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 date de début ne peut pas être dans le passé"
)
) 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).
" Vérifier les clients
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 = 'Le client est requis"
)
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD setStatusNew.
" Définir le statut sur 'Open' lors de la création
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

- Name: ZUI_TRAVEL_O4
- Binding Type: 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 = 'Mis à jour"
) )
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).

Éléments de Behavior

Actions

" Instance-Action (sur une ligne)
action acceptTravel result [1] $self;
" Static Action (sans instance)
static action createFromTemplate result [1] $self;
" Factory Action (crée une nouvelle instance)
factory action copyTravel [1];
" Avec paramètres
action setStatus parameter ZA_StatusParameter result [1] $self;

Validations

" Lors de Save
validation validateDates on save { field BeginDate, EndDate; }
" Lors de Modify (vérification immédiate)
validation validatePrice on modify { field TotalPrice; }
" Draft-Validations
draft validation validateConsistency on save;

Determinations

" Lors de Create
determination setDefaults on modify { create; }
" Lors de modification de champ
determination calculateTotal on modify { field Quantity, Price; }
" Lors de Save
determination generateNumber on save { create; }

Feature Control

" Features globaux
field ( readonly ) TravelId;
field ( mandatory ) CustomerId;
field ( readonly : update ) AgencyId;
" Instance-Features (dynamique)
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 (automatiquement disponibles)
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft action Resume;
draft determine action Prepare;
}

Classes importantes

ClasseDescription
cl_abap_behavior_handlerClasse de base pour Behavior Implementation
cl_abap_context_infoContexte système (Date, User)
if_abap_behvConstantes (fc-o-enabled, mk-on)
if_abap_behv_messageMessage-Severity

Points importants / Bonnes pratiques

  • Scénario Managed pour les nouveaux développements – le framework gère le CRUD.
  • Interface Views (I_*) pour le modèle de données, Projection Views (C_*) pour UI/API.
  • EML (Entity Manipulation Language) pour l’accès programmatique au BO.
  • Validations pour les règles métier, Determinations pour les valeurs automatiques.
  • Actions pour les opérations métier au-delà du CRUD.
  • Feature Control pour la disponibilité dynamique des champs/actions.
  • Draft pour la sauvegarde intermédiaire lors de saisies complexes.
  • Utilisez IN LOCAL MODE pour l’accès sans vérification d’autorisation.
  • FAILED et REPORTED pour la gestion d’erreurs et les messages.
  • Strict Mode (strict ( 2 )) pour la validation des bonnes pratiques.
  • Combinez avec CDS Views pour le modèle de données.