RAP: Data Model & Behavior

The ABAP RESTful Application Programming Model is SAP's standard for building transactional Fiori apps, OData/Web APIs, and released business objects — on S/4HANA (1909+ with growing features; recommended 2022+) and BTP ABAP Environment.

34.1 What is RAP?

The ABAP RESTful Application Programming Model is SAP's standard for building transactional Fiori apps, OData/Web APIs, and released business objects — on S/4HANA (1909+ with growing features; recommended 2022+) and BTP ABAP Environment. It replaces the CDS + BOPF model and SEGW-based OData.

┌──────────────────────────────────────────────────────────────┐
│ Service consumption: Fiori elements UI, Web API, EML           │
├──────────────────────────────────────────────────────────────┤
│ Business service: Service binding (OData V2/V4, UI/API)        │
│                   Service definition (exposed entities)        │
├──────────────────────────────────────────────────────────────┤
│ Business object: projection views + projection behavior         │
│                  root/child CDS view entities (data model)      │
│                  behavior definition (BDEF) + implementation    │
├──────────────────────────────────────────────────────────────┤
│ Database tables (active + draft)                                │
└──────────────────────────────────────────────────────────────┘

34.2 Implementation types

Who handles CRUD & save RAP framework (you add validations, determinations, actions) Greenfield apps on new tables Managed with unmanaged save

Framework buffer, your own save (e.g. call function modules) New BO over legacy persistence

You implement the transactional buffer and save Wrap existing legacy logic (BAPIs, function modules)

Draft-enabled (managed or unmanaged) Framework stores drafts in a draft table

Fiori apps with editing sessions, autosave

34.3 Data model (root and child)

-- Tables: zrap_travel (key travel_uuid) and zrap_booking (key booking_uuid, parent travel_uuid)

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Travel - root'
define root view entity ZR_Travel
  as select from zrap_travel
  composition [0..*] of ZR_Booking as _Booking
  association [0..1] to /DMO/I_Agency as _Agency on $projection.AgencyID = _Agency.AgencyID
{
  key travel_uuid           as TravelUUID,
      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,
      currency_code         as CurrencyCode,
      overall_status        as OverallStatus,
      @Semantics.user.createdBy: true
      local_created_by      as LocalCreatedBy,
      @Semantics.systemDateTime.localInstanceLastChangedAt: true
      local_last_changed_at as LocalLastChangedAt,
      @Semantics.systemDateTime.lastChangedAt: true
      last_changed_at       as LastChangedAt,
      _Booking,
      _Agency
}
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Booking - child'
define view entity ZR_Booking
  as select from zrap_booking
  association to parent ZR_Travel as _Travel on $projection.TravelUUID = _Travel.TravelUUID
{
  key booking_uuid  as BookingUUID,
      travel_uuid   as TravelUUID,
      booking_id    as BookingID,
      flight_date   as FlightDate,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      flight_price  as FlightPrice,
      currency_code as CurrencyCode,
      _Travel
}

34.4 Behavior definition (BDEF)

Building blocks: operations (create/update/delete, actions, functions), determinations (compute values on modify/save), validations (check on save), feature control (static/instance/global: enable/disable fields and operations), authorization, numbering (managed UUID, early/late numbering), locking & ETags (optimistic concurrency), side effects, business events (event + RAISE ENTITY EVENT), determine actions.

managed implementation in class zbp_r_travel unique;
strict ( 2 );
with draft;

define behavior for ZR_Travel alias Travel
persistent table zrap_travel
draft table zrap_travel_d
lock master total etag LastChangedAt
authorization master ( instance )
etag master LocalLastChangedAt
{
  create;
  update;
  delete;
  association _Booking { create; with draft; }

  field ( numbering : managed, readonly ) TravelUUID;
  field ( readonly ) TravelID, OverallStatus, TotalPrice, LocalLastChangedAt, LastChangedAt;
  field ( mandatory ) CustomerID, BeginDate, EndDate;

  determination setTravelID on save { create; }
  determination setInitialStatus on modify { create; }
  validation validateDates on save { create; field BeginDate, EndDate; }

  action ( features : instance ) acceptTravel result [1] $self;
  action ( features : instance ) rejectTravel result [1] $self;
  internal action recalcTotalPrice;

  draft action Edit;
  draft action Activate optimized;
  draft action Discard;
  draft action Resume;
  draft determine action Prepare { validation validateDates; }

  mapping for zrap_travel corresponding
  {
    TravelUUID = travel_uuid;
    TravelID = travel_id;
    AgencyID = agency_id;
   
…

34.5 Behavior implementation (behavior pool)

The class ZBP_R_TRAVEL (FOR BEHAVIOR OF ZR_Travel) contains local handler classes:

Derived types and components: %tky (transactional key incl. %is_draft), %key, %cid (content ID for new instances), %control, %param, %msg, %element, %fail; response parameters mapped, failed, reported. For unmanaged BOs you also implement a saver class (cl_abap_behavior_saver) with finalize, check_before_save, save, cleanup.

CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
  PRIVATE SECTION.
    METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
      IMPORTING keys REQUEST requested_authorizations FOR Travel RESULT result.
    METHODS get_instance_features FOR INSTANCE FEATURES
      IMPORTING keys REQUEST requested_features FOR Travel RESULT result.
    METHODS acceptTravel FOR MODIFY
      IMPORTING keys FOR ACTION Travel~acceptTravel RESULT result.
    METHODS rejectTravel FOR MODIFY
      IMPORTING keys FOR ACTION Travel~rejectTravel RESULT result.
    METHODS setInitialStatus FOR DETERMINE ON MODIFY
      IMPORTING keys FOR Travel~setInitialStatus.
    METHODS setTravelID FOR DETERMINE ON SAVE
      IMPORTING keys FOR Travel~setTravelID.
    METHODS validateDates FOR VALIDATE ON SAVE
      IMPORTING keys FOR Travel~validateDates.
    METHODS recalcTotalPrice FOR MODIFY
      IMPORTING keys FOR ACTION Travel~recalcTotalPrice.
ENDCLASS.

CLASS lhc_travel IMPLEMENTATION.

  METHOD get_instance_authorizations.
    " allow everything in this demo
  ENDMETHOD.

  METHOD setInitialStatus.
    READ ENTITIES OF zr_travel IN LOCAL MODE
      ENTITY Travel FIELDS ( OverallSt
…

34.6 Entity Manipulation Language (EML)

EML accesses RAP BOs from ABAP — inside behavior pools (IN LOCAL MODE) or from other code (reports, classes, other BOs):

Rules: never use COMMIT WORK/ROLLBACK WORK inside behavior handlers (the framework controls the LUW); outside RAP handlers use COMMIT ENTITIES. Released SAP BOs (e.g. I_BankTP, I_SalesOrderTP depending on release) are consumed the same way.

" Create with a child
MODIFY ENTITIES OF zr_travel
  ENTITY Travel
    CREATE FIELDS ( CustomerID BeginDate EndDate CurrencyCode )
    WITH VALUE #( ( %cid = 'T1' CustomerID = '000001'
                    BeginDate = '20260101' EndDate = '20260110' CurrencyCode = 'EUR' ) )
    CREATE BY \_Booking FIELDS ( FlightDate FlightPrice CurrencyCode )
    WITH VALUE #( ( %cid_ref = 'T1'
                    %target  = VALUE #( ( %cid = 'B1' FlightDate = '20260101'
                                          FlightPrice = 250 CurrencyCode = 'EUR' ) ) ) )
  MAPPED DATA(mapped)
  FAILED DATA(failed)
  REPORTED DATA(reported).

IF failed IS INITIAL.
  COMMIT ENTITIES RESPONSE OF zr_travel FAILED DATA(commit_failed) REPORTED DATA(commit_reported).
ENDIF.

" Read, including by association
READ ENTITIES OF zr_travel
  ENTITY Travel ALL FIELDS WITH VALUE #( ( TravelUUID = lv_uuid ) ) RESULT DATA(travels)
  ENTITY Travel BY \_Booking ALL FIELDS WITH VALUE #( ( TravelUUID = lv_uuid ) ) RESULT DATA(bookings).

" Execute an action
MODIFY ENTITIES OF zr_travel
  ENTITY Travel EXECUTE acceptTravel FROM VALUE #( ( TravelUUID = lv_uuid ) )
  RESULT DATA(action_result).
COMMIT ENTITIES.