ABAP RAP Grundlagen: RESTful ABAP Programming

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

RAP (RESTful ABAP Programming) ist das moderne Programmiermodell für transaktionale Anwendungen in SAP. Es bildet die Grundlage für SAP Fiori Apps, OData Services und Cloud-Entwicklung auf SAP BTP.

Grundkonzepte

  • Business Object (BO): Fachliches Objekt mit Daten und Verhalten
  • CDS View: Datenmodell (siehe CDS Views)
  • Behavior Definition (BDEF): Deklariert das Verhalten (CRUD, Actions, Validations)
  • Behavior Implementation (BIL): Implementiert das Verhalten in ABAP

RAP-Architektur

┌─────────────────────────────────────────────┐
│ 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

AspektManagedUnmanaged
CRUDAutomatisch vom FrameworkManuell implementieren
TransaktionenFramework-gesteuertEigene Kontrolle
AufwandGeringHöher
FlexibilitätStandard-OperationenVolle Kontrolle
Empfohlen fürNeue EntwicklungenLegacy-Integration

Beispiel: Managed Szenario

1. Datenbanktabelle

@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
{
// Standard-Operationen
create;
update;
delete;
// Feldmapping für Datenbank
field ( readonly ) TravelId;
field ( readonly ) CreatedBy, CreatedAt, LastChangedBy, LastChangedAt;
// Automatische Nummernvergabe
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.
" Lese aktuelle Daten
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel)
FAILED failed.
" Feature-Control basierend auf Status
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.
" Status auf 'Accepted' setzen
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.
" Ergebnis zurückgeben
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.
" Daten lesen
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).
" Enddatum muss nach Beginn liegen
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 = 'Enddatum muss nach Beginndatum liegen'
)
) TO reported-travel.
ENDIF.
" Beginn darf nicht in der Vergangenheit liegen
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 = 'Beginndatum darf nicht in der Vergangenheit liegen'
)
) 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).
" Kunden prüfen
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 = 'Kunde ist erforderlich'
)
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD setStatusNew.
" Bei Neuanlage Status auf 'Open' setzen
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 = 'Aktualisiert'
) )
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).

Behavior-Elemente

Actions

" Instanz-Action (auf eine Zeile)
action acceptTravel result [1] $self;
" Statische Action (ohne Instanz)
static action createFromTemplate result [1] $self;
" Factory Action (erstellt neue Instanz)
factory action copyTravel [1];
" Mit Parametern
action setStatus parameter ZA_StatusParameter result [1] $self;

Validations

" Bei Save
validation validateDates on save { field BeginDate, EndDate; }
" Bei Modify (sofortige Prüfung)
validation validatePrice on modify { field TotalPrice; }
" Draft-Validations
draft validation validateConsistency on save;

Determinations

" Bei Create
determination setDefaults on modify { create; }
" Bei Feldänderung
determination calculateTotal on modify { field Quantity, Price; }
" Bei Save
determination generateNumber on save { create; }

Feature Control

" Globale Features
field ( readonly ) TravelId;
field ( mandatory ) CustomerId;
field ( readonly : update ) AgencyId;
" Instanz-Features (dynamisch)
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 (automatisch verfügbar)
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft action Resume;
draft determine action Prepare;
}

Wichtige Klassen

KlasseBeschreibung
cl_abap_behavior_handlerBasisklasse für Behavior Implementation
cl_abap_context_infoSystem-Kontext (Datum, User)
if_abap_behvKonstanten (fc-o-enabled, mk-on)
if_abap_behv_messageMessage-Severity

Wichtige Hinweise / Best Practice

  • Managed Szenario für neue Entwicklungen – Framework übernimmt CRUD.
  • Interface Views (I_*) für Datenmodell, Projection Views (C_*) für UI/API.
  • EML (Entity Manipulation Language) für programmatischen BO-Zugriff.
  • Validations für Geschäftsregeln, Determinations für automatische Werte.
  • Actions für Geschäftsoperationen jenseits von CRUD.
  • Feature Control für dynamische Feld-/Aktionsverfügbarkeit.
  • Draft für Zwischenspeicherung bei komplexen Eingaben.
  • Nutzen Sie IN LOCAL MODE für Zugriff ohne Berechtigungsprüfung.
  • FAILED und REPORTED für Fehlerbehandlung und Nachrichten.
  • Strict Mode (strict ( 2 )) für Best-Practice-Validierung.
  • Kombinieren Sie mit CDS Views für das Datenmodell.