mcpField
A
abap-rap

abap-rap

github.com/dankrompDevelopment837 installsUpdated 9w ago
Repository

About abap-rap

abap-rap is a best-practices reference for developers building SAP ABAP RESTful Application Programming Model (RAP) applications. It covers the layered architecture, implementation choices, key artifacts, and common mistakes to avoid.

Key features

  1. 01RAP three-layer architecture
  2. 02Managed and unmanaged implementation guidance
  3. 03CDS view entity patterns
  4. 04Behavior definition and implementation examples
  5. 05Projection and service setup guidance
  6. 06Common pitfalls and safeguards

Use cases

  1. 01Choosing managed or unmanaged RAP
  2. 02Structuring RAP business objects
  3. 03Reviewing behavior definitions and handlers
  4. 04Avoiding common RAP implementation errors

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/dankromp/skilloverflow --skill abap-rap

After installing, type/abap-rapin Claude Code to confirm it loaded.

Bundled filesreferences/quick-reference.mdtemplates/managed-rap-bo.abap

Details

From the project README

ABAP RAP — Best Practices

Primary reference: https://help.sap.com/docs/abap-cloud/abap-rap BDEF syntax: https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abenbdl_define_beh.htm Cheat sheets: https://github.com/SAP-samples/abap-cheat-sheets

RAP architecture — three layers

RAP business objects are defined through CDS data modeling views, CDS behavior definitions, and behavior implementations in ABAP classes.

Database table          (DDIC table — stores active data)
    ↓
CDS view entity         (data model — root + child entities)
    ↓
Behavior Definition     (BDEF — what operations are allowed)
    ↓
Behavior Implementation (ABAP class — business logic)
    ↓
Projection view         (UI-specific subset + aliases)
    ↓
Service Definition      (what to expose)
    ↓
Service Binding         (OData V2 or V4 protocol)

Managed vs Unmanaged — choose carefully

In Managed RAP, the framework automatically handles all CRUD persistence — the developer focuses only on business logic. In Unmanaged RAP, the developer must implement each save operation manually. Managed RAP is ideal for new development; Unmanaged is chosen when integrating complex existing logic or legacy systems.

Use Managed when: greenfield development, direct table access, new S/4HANA or BTP apps Use Unmanaged when: integrating existing BAPI/function modules, complex legacy logic, external persistence


CDS view entity — root and child

" Root CDS view entity
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Travel'
define root view entity ZI_Travel
  as select from ztravel
  composition [0..*] of ZI_TravelItem as _Items
{
  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,
      booking_fee        as BookingFee,
      total_price        as TotalPrice,
      currency_code      as CurrencyCode,
      overall_status     as OverallStatus,
      @Semantics.systemDateTime.createdAt: true
      created_at         as CreatedAt,
      @Semantics.user.createdBy: true
      created_by         as CreatedBy,
      @Semantics.systemDateTime.lastChangedAt: true
      last_changed_at    as LastChangedAt,
      @Semantics.user.lastChangedBy: true
      last_changed_by    as LastChangedBy,
      @Semantics.systemDateTime.localInstanceLastChangedAt: true
      local_last_changed_at as LocalLastChangedAt,
      _Items
}

Behavior Definition — Managed with Draft

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

define behavior for ZI_Travel alias Travel
  persistent table ztravel
  draft table ztravel_d
  etag master LocalLastChangedAt
  lock master total etag LastChangedAt
  authorization master ( global )
{
  field ( readonly ) TravelUUID, TravelID, CreatedAt, CreatedBy, LastChangedAt, LastChangedBy;
  field ( numbering : managed, readonly ) TravelUUID;

  create;
  update;
  delete;

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

  validation validateDates on save { field BeginDate, EndDate; }
  validation validateStatus on save { field OverallStatus; }

  determination calculateTotalPrice on modify { field BookingFee; }

  draft action Edit;
  draft action Activate optimized;
  draft action Discard;
  draft action Resume;

  association _Items { create; with draft; }

  mapping for ztravel {
    TravelUUID = travel_uuid;
    TravelID   = travel_id;
    AgencyID   = agency_id;
  }
}

Behavior Implementation — key methods

CLASS ZBP_Travel DEFINITION PUBLIC ABSTRACT FINAL FOR BEHAVIOR OF ZI_Travel.
  PUBLIC SECTION.
    " Validation
    METHODS validateDates    FOR VALIDATE ON SAVE
      IMPORTING keys FOR Travel~validateDates.
    " Determination
    METHODS calculateTotalPrice FOR DETERMINE ON MODIFY
      IMPORTING keys FOR Travel~calculateTotalPrice.
    " Action
    METHODS acceptTravel     FOR MODIFY
      IMPORTING keys FOR ACTION Travel~acceptTravel RESULT result.
ENDCLASS.

CLASS ZBP_Travel IMPLEMENTATION.
  METHOD validateDates.
    READ ENTITIES OF ZI_Travel IN LOCAL MODE
      ENTITY Travel
        FIELDS ( BeginDate EndDate )
        WITH CORRESPONDING #( keys )
      RESULT DATA(lt_travel)
      FAILED failed.

    LOOP AT lt_travel INTO DATA(ls_travel).
      IF ls_travel-EndDate < ls_travel-BeginDate.
        APPEND VALUE #(
          %tky = ls_travel-%tky )
          TO failed-travel.
        APPEND VALUE #(
          %tky        = ls_travel-%tky
          %state_area = 'VALIDATE_DATES'
          %msg        = new_message_with_text(
                          severity = if_abap_behv_message=>severity-error
                          text     = 'End date must be after begin date' )
          %element-EndDate = if_abap_behv=>mk-on )
          TO reported-travel.
      ENDIF.
    ENDLOOP.
  ENDMETHOD.

  METHOD calculateTotalPrice.
    " Always use IN LOCAL MODE inside behavior handlers
    MODIFY ENTITIES OF ZI_Travel IN LOCAL MODE
      ENTITY Travel
        UPDATE FIELDS ( TotalPrice )
        WITH VALUE #( FOR key IN keys (
          %tky       = key-%tky
          TotalPrice = '0.00' ) ).
  ENDMETHOD.

  METHOD acceptTravel.
    MODIFY ENTITIES OF ZI_Travel IN LOCAL MODE
      ENTITY Travel
        UPDATE FIELDS ( OverallStatus )
        WITH VALUE #( FOR key IN keys (
          %tky          = key-%tky
          OverallStatus = 'A' ) )
      FAILED   failed
      REPORTED reported.

    READ ENTITIES OF ZI_Travel IN LOCAL MODE
      ENTITY Travel ALL FIELDS WITH CORRESPONDING #( keys )
      RESULT result
      FAILED failed.
  ENDMETHOD.
ENDCLASS.

Projection view + BDEF

" Projection CDS view (UI-facing)
@EndUserText.label: 'Travel - Projection'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define root view entity ZC_Travel
  provider contract transactional_ui
  as projection on ZI_Travel
{
  key TravelUUID,
      TravelID,
      @UI.lineItem: [{ position: 10 }]
      @UI.selectionField: [{ position: 10 }]
      AgencyID,
      BeginDate,
      EndDate,
      @UI.lineItem: [{ position: 50, criticality: 'OverallStatusCriticality' }]
      OverallStatus,
      _Items : redirected to composition child ZC_TravelItem
}

" Projection BDEF — thin layer, no business logic here
projection;
strict ( 2 );
use draft;

define behavior for ZC_Travel alias Travel
{
  use create;
  use update;
  use delete;
  use action acceptTravel;
  use action rejectTravel;
  use draft action Edit;
  use draft action Activate;
  use draft action Discard;
  use draft action Resume;
  use association _Items { create; with draft; }
}

Service Definition + Binding

" Service Definition
@EndUserText.label: 'Travel Service'
define service ZUI_Travel_O4 {
  expose ZC_Travel as Travel;
  expose ZC_TravelItem as TravelItem;
  expose /DMO/I_Agency as Agency;
}

Activate the Service Binding ZUI_Travel_O4_VR as OData V4 UI binding in ADT.


Common mistakes to avoid

  • ❌ Adding business logic in the projection BDEF or projection view

  • ✅ Keep projection thin — UI labels, field aliases, and use statements only. Interface behavior = business logic layer.

  • ❌ Calling MODIFY ENTITIES without IN LOCAL MODE inside a handler

  • ✅ Always use IN LOCAL MODE for internal modifications to avoid authority checks and lock issues

  • ❌ Skipping draft handling and adding it later

  • ✅ Enable draft from the start — retrofitting draft into an existing RAP BO is complex

  • ❌ Using strict ( 1 ) in new development

  • ✅ Always use strict ( 2 ) — enables the most comprehensive BDEF syntax checks

  • ❌ Implementing CRUD in unmanaged when you have direct table access

  • ✅ Use managed implementation for greenfield with direct table access

  • ❌ Forgetting etag master and lock master in the root BDEF

  • ✅ Always define ETag for optimistic locking and lock master for draft

  • ❌ Missing @Semantics.systemDateTime and @Semantics.user annotations on admin fields

  • ✅ These annotations are required for managed RAP to auto-populate timestamps and users

Comments

Markdown supported