Imported from likweitan/abap-skills (
skills/rap/SKILL.md). Install upstream withnpx skills add likweitan/abap-skills --skill rap. Copyright stays with the author.
RAP (RESTful ABAP Programming Model)
Guide for building transactional applications using the ABAP RESTful Application Programming Model (RAP) in ABAP Cloud.
Workflow
-
Determine the user's goal:
- Creating a new RAP BO from scratch
- Adding behavior (actions, validations, determinations) to an existing BO
- Writing EML statements to consume a RAP BO
- Troubleshooting RAP-related issues
- Understanding RAP concepts
-
Identify the scenario:
- Managed (greenfield) vs. unmanaged (brownfield)
- Draft-enabled or not
- Numbering concept: early/late, internal/external/managed
- Single entity or composition tree (root + children)
-
Guide implementation following the RAP layered architecture:
- Data modeling (database tables → CDS view entities)
- Behavior definition (BDEF using BDL)
- Behavior implementation (ABAP behavior pool)
- Business service exposure (service definition → service binding)
-
Provide code examples using correct BDL and EML syntax
RAP Architecture Layers
| Layer | Artifacts | Purpose |
|---|---|---|
| Data Modeling | Database tables, CDS root/child view entities | Data persistence and semantic data model |
| Behavior Definition | BDEF (.bdef) |
Declares transactional behavior (operations, characteristics) using BDL |
| Behavior Implementation | ABAP behavior pool (BP_*) |
Implements business logic in handler/saver classes |
| Projection | CDS projection views, projection BDEF | Adapts BO for specific service consumers |
| Business Service | Service definition, service binding | Exposes BO as OData service |
Implementation Types
Managed (Greenfield)
- Framework handles transactional buffer and standard CRUD operations automatically
- Only need custom code for non-standard operations (actions, validations, determinations)
- Automatic save handling (can be enhanced with
additional saveor replaced withunmanaged save)
managed implementation in class zbp_r_entity unique;
strict ( 2 );
Unmanaged (Brownfield)
- Developer provides transactional buffer and implements all operations
- Used when existing business logic needs to be embedded in RAP
unmanaged implementation in class zbp_r_entity unique;
strict ( 2 );
Behavior Definition (BDL) Quick Reference
Complete BDEF Structure
managed implementation in class zbp_r_root unique;
strict ( 2 );
with draft;
define behavior for ZR_Root alias Root
persistent table zroot_tab
draft table zroot_d
etag master LocalLastChangedAt
lock master
total etag LastChangedAt
authorization master ( global )
late numbering
{
// Field characteristics
field ( readonly ) RootUUID, CreatedBy, CreatedAt, LastChangedBy, LastChangedAt;
field ( mandatory ) Description;
field ( numbering : managed ) RootUUID;
// Standard operations
create;
update;
delete;
// Association to child entity
association _Child { create; }
// Actions
action doSomething result [1] $self;
static action createFromTemplate parameter ZD_CreateParam result [1] $self;
internal action recalculate;
// Validations
validation validateDescription on save { create; field Description; }
// Determinations
determination setDefaults on modify { create; }
determination calcTotal on modify { field Quantity, Price; }
// Draft actions
draft action Resume;
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft determine action Prepare
{
validation validateDescription;
}
// Side effects
side effects
{
field Quantity affects field TotalAmount;
field Price affects field TotalAmount;
determine action Prepare executed on field Description affects messages;
}
// Events
event created;
event deleted parameter ZD_DeletedEvent;
// Mapping
mapping for zroot_tab corresponding
{
RootUUID = root_uuid;
Description = description;
}
}
define behavior for ZR_Child alias Child
persistent table zchild_tab
draft table zchild_d
etag master LocalLastChangedAt
lock dependent by _Root
authorization dependent by _Root
{
field ( readonly ) ChildUUID, RootUUID;
field ( numbering : managed ) ChildUUID;
update;
delete;
association _Root;
mapping for zchild_tab corresponding
{
ChildUUID = child_uuid;
RootUUID = root_uuid;
}
}
Projection BDEF
projection;
strict ( 2 );
use draft;
define behavior for ZC_Root alias Root
{
use create;
use update;
use delete;
use action doSomething;
use association _Child { create; }
}
define behavior for ZC_Child alias Child
{
use update;
use delete;
use association _Root;
}
Key BDL Elements
| Element | Syntax | Purpose |
|---|---|---|
| Managed numbering | field ( numbering : managed ) KeyField; |
Framework assigns UUID keys automatically |
| Early numbering | early numbering |
Custom key assignment in interaction phase via FOR NUMBERING handler |
| Late numbering | late numbering |
Key assignment in save sequence via adjust_numbers saver method |
| Lock master | lock master |
Root entity controls pessimistic locking |
| Lock dependent | lock dependent by _Assoc |
Child entity delegates locking to parent |
| ETag | etag master FieldName |
Optimistic concurrency control |
| Total ETag | total etag FieldName |
Required for draft-enabled BOs |
| Draft | with draft; |
Enables draft handling for entire BO |
| Collaborative draft | with collaborative draft; |
Multi-user draft editing |
| Strict mode | strict ( 2 ); |
Enables additional BDL syntax checks (use latest version) |
ABAP Behavior Pool (ABP)
Handler Class
CLASS lhc_root DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
" Standard operations (unmanaged only)
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE Root.
" Action implementation
METHODS doSomething FOR MODIFY
IMPORTING keys FOR ACTION Root~doSomething RESULT result.
" Validation
METHODS validateDescription FOR VALIDATE ON SAVE
IMPORTING keys FOR Root~validateDescription.
" Determination
METHODS setDefaults FOR DETERMINE ON MODIFY
IMPORTING keys FOR Root~setDefaults.
" Instance feature control
METHODS get_instance_features FOR INSTANCE FEATURES
IMPORTING keys REQUEST requested_features FOR Root RESULT result.
" Instance authorization
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR Root RESULT result.
ENDCLASS.
CLASS lhc_root IMPLEMENTATION.
METHOD doSomething.
" Read current instance data
READ ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(entities)
FAILED failed.
" Modify instances
MODIFY ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
UPDATE FIELDS ( Status )
WITH VALUE #( FOR entity IN entities
( %tky = entity-%tky
Status = 'DONE'
%control-Status = if_abap_behv=>mk-on ) )
FAILED failed
REPORTED reported.
" Fill result
result = VALUE #( FOR entity IN entities
( %tky = entity-%tky
%param = entity ) ).
ENDMETHOD.
METHOD validateDescription.
READ ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
FIELDS ( Description ) WITH CORRESPONDING #( keys )
RESULT DATA(entities).
LOOP AT entities INTO DATA(entity).
IF entity-Description IS INITIAL.
APPEND VALUE #( %tky = entity-%tky ) TO failed-root.
APPEND VALUE #( %tky = entity-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Description must not be empty' )
%element-Description = if_abap_behv=>mk-on
) TO reported-root.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD setDefaults.
READ ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(entities).
MODIFY ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
UPDATE FIELDS ( Status CreatedAt )
WITH VALUE #( FOR entity IN entities
( %tky = entity-%tky
Status = 'NEW'
%control-Status = if_abap_behv=>mk-on ) )
REPORTED reported.
ENDMETHOD.
ENDCLASS.
Saver Class
CLASS lsc_root DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS finalize REDEFINITION.
METHODS check_before_save REDEFINITION.
METHODS save_modified REDEFINITION.
METHODS cleanup REDEFINITION.
METHODS cleanup_finalize REDEFINITION.
ENDCLASS.
CLASS lsc_root IMPLEMENTATION.
METHOD finalize.
" Final calculations before save
ENDMETHOD.
METHOD check_before_save.
" Final consistency checks
ENDMETHOD.
METHOD save_modified.
" Only needed for 'with additional save' or 'with unmanaged save'
" Raise business events here
IF create-root IS NOT INITIAL.
RAISE ENTITY EVENT zr_root~created
FROM VALUE #( FOR <cr> IN create-root
( %key = VALUE #( RootUUID = <cr>-RootUUID ) ) ).
ENDIF.
ENDMETHOD.
METHOD cleanup.
" Clear transactional buffer
ENDMETHOD.
METHOD cleanup_finalize.
" Rollback finalize changes on failure
ENDMETHOD.
ENDCLASS.
EML (Entity Manipulation Language) Quick Reference
EML is the ABAP language for programmatically interacting with RAP BOs. Key operations: MODIFY ENTITY (create/update/delete/execute action), READ ENTITIES, COMMIT ENTITIES, ROLLBACK ENTITIES.
- Create:
MODIFY ENTITY ... CREATE FIELDS ( ... ) WITH VALUE #( ( %cid = '...' ... ) ) - Read:
READ ENTITIES OF ... ALL FIELDS WITH VALUE #( ( key = val ) ) RESULT DATA(result) - Update:
MODIFY ENTITY ... UPDATE FIELDS ( ... ) WITH VALUE #( ( %tky = ... ) ) - Delete:
MODIFY ENTITY ... DELETE FROM VALUE #( ( %tky = ... ) ) - Execute Action:
MODIFY ENTITY ... EXECUTE actionName FROM VALUE #( ( %tky = ... ) ) - Deep Create: Use
CREATE BY \_Assocwith%cid_refand%target
For full EML syntax with code examples, read references/eml-quick-reference.md.
Draft Handling
- Enabled via
with draft;in BDEF header - Requires separate
draft tablefor each entity - Draft table must include
"%admin": include sych_bdl_draft_admin_inc; - Draft actions (
Edit,Activate,Discard,Resume,Prepare) are implicitly provided - Use
%is_draftcomponent (or%tkywhich includes it) to distinguish draft vs. active instances
RAP Save Sequence
| Phase | Methods Called | Purpose |
|---|---|---|
| Early Save | finalize → check_before_save → (on failure: cleanup_finalize) |
Ensure data consistency |
| Late Save | adjust_numbers → save / save_modified → cleanup |
Persist data to database |
- Early save failures (sy-subrc = 4) return to interaction phase
- Late save is point of no return — either commit succeeds or runtime error
Key BDEF Derived Type Components
| Component | Purpose |
|---|---|
%cid |
Content ID — unique preliminary identifier for new instances |
%cid_ref |
Reference to a %cid in the same EML request |
%key |
Primary key fields |
%tky |
Transactional key (%key + %is_draft + %pid) — recommended |
%data |
All key and data fields |
%control |
Flags indicating which fields are provided/requested |
%is_draft |
Draft indicator (draft-enabled BOs only) |
%pid |
Preliminary ID (late numbering only) |
%target |
Target instances for create-by-association |
%param |
Action/function parameter values |
Best Practices
- Always use
strict ( 2 );for new BOs - Prefer
%tkyover%keyfor future-proof code (handles draft/late numbering transitions) - Always fill
%cidin create operations even if not referenced later - Use
IN LOCAL MODEin handler methods to bypass feature controls and authorization checks - Implement validations for data consistency checks, determinations for calculated fields
- Keep handler methods focused; use ABP auxiliary classes for shared logic
- For managed BOs, only implement handler methods for non-standard operations