RAP Basics Part 11: Draft, Locking and Authorization
Make a RAP BO safe for real multi-user use: draft handling (draft tables, Edit/Activate/Discard/Resume/Prepare, total ETag), pessimistic locking (lock master) and optimistic concurrency (ETags), and authorization at two levels — read access via CDS DCL and modify access via authorization master (global/instance).
Explanation
📌 KEY POINTS
✅ Draft lets users save incomplete work on the server: changes live in a draft table until Activate copies them to the active table.
✅ Locking: lock master takes an exclusive lock on the active instance (for draft: when editing starts); ETags detect that the data changed since it was read.
✅ Draft needs a total ETag (lock master total etag LastChangedAt) to detect changes to the active instance while a draft exists.
✅ Authorization has two parts: read = CDS access control (DCL); create/update/delete/actions = authorization master in the BDEF (global and/or instance methods).
⚠️ A BO with DCL but no authorization master lets every user who can open the app change every record they can see.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Final part: making the BO ready for many users working at the same time.
━━━━━━━━━━━━━━━━━━━━
▶ 1. DRAFT
- BDEF header: with draft; entity: draft table ztravel_d (generated via quick fix).
- Draft actions: Edit, Activate optimized, Discard, Resume, Prepare.
- Children: association _Booking { create; with draft; }.
- %is_draft in %tky distinguishes draft and active instances.
━━━━━━━━━━━━━━━━━━━━
▶ 2. LOCKING
- Pessimistic: lock master on root, lock dependent by _Travel on children.
- Managed BO: framework sets the enqueue lock; unmanaged: implement lock method.
- With draft the lock is held from Edit until Activate/Discard (draft lifetime).
━━━━━━━━━━━━━━━━━━━━
▶ 3. ETAGS (OPTIMISTIC)
- etag master LocalLastChangedAt — instance ETag in OData (If-Match header).
- total etag LastChangedAt — for draft; checked on Resume/Activate.
- Outdated ETag → HTTP 412 / "data changed by another user".
━━━━━━━━━━━━━━━━━━━━
▶ 4. AUTHORIZATION — READ
- @AccessControl.authorizationCheck: #CHECK + DCL role with pfcg_auth mapping.
- Restricts which rows a user can see (Part 8 of CDS Views).
━━━━━━━━━━━━━━━━━━━━
▶ 5. AUTHORIZATION — MODIFY
- authorization master ( global, instance ) on the root; children authorization dependent.
- get_global_authorizations: may the user create at all?
- get_instance_authorizations: may the user update/delete/accept this record (e.g. by agency)?
- Use AUTHORITY-CHECK on your own authorization object.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Add with draft; and create draft tables via quick fix.
- Add total etag and draft actions, include Prepare validations.
- Add authorization master ( global, instance ) and implement both methods.
- Create a DCL role for read access.
- Test with two users: edit the same travel, and a user without authorization.
✅ CHECKPOINT: user B sees "locked by user A" while A edits, and a user without the auth object cannot create travels.
Code example
// ===== STEP 1: BDEF header and root with draft, locks, ETags, authorization =====managed implementation in class zbp_i_travel unique;strict ( 2 );with draft; define behavior for ZI_Travel alias Travelpersistent table ztravel_adraft table ztravel_dlock master total etag LastChangedAtauthorization master ( global, instance )etag master LocalLastChangedAt{ create; update; delete; association _Booking { create; with draft; } draft action Edit; draft action Activate optimized; draft action Discard; draft action Resume; draft determine action Prepare;} * ===== STEP 2: global authorization - may the user create at all? ===== METHOD get_global_authorizations. IF requested_authorizations-%create = if_abap_behv=>mk-on. AUTHORITY-CHECK OBJECT 'ZTRAVEL' ID 'ACTVT' FIELD '01'. IF sy-subrc = 0. result-%create = if_abap_behv=>auth-allowed. ELSE. result-%create = if_abap_behv=>auth-unauthorized. ENDIF. ENDIF. ENDMETHOD. * ===== STEP 3: instance authorization - per agency ===== METHOD get_instance_authorizations. DATA lt_travel TYPE TABLE FOR READ RESULT zi_travel\travel. DATA ls_travel LIKE LINE OF lt_travel. DATA ls_result LIKE LINE OF result. READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel FIELDS ( AgencyID ) WITH CORRESPONDING #( keys ) RESULT lt_travel. LOOP AT lt_travel INTO ls_travel. CLEAR ls_result. ls_result-%tky = ls_travel-%tky. AUTHORITY-CHECK OBJECT 'ZTRAVEL' ID 'ACTVT' FIELD '02' ID 'AGENCY' FIELD ls_travel-AgencyID. IF sy-subrc = 0. ls_result-%update = if_abap_behv=>auth-allowed. ls_result-%delete = if_abap_behv=>auth-allowed. ELSE. ls_result-%update = if_abap_behv=>auth-unauthorized. ls_result-%delete = if_abap_behv=>auth-unauthorized. ENDIF. APPEND ls_result TO result. ENDLOOP. ENDMETHOD. // ===== STEP 4: DCL for read access =====@EndUserText.label: 'Travel read access by agency'@MappingRole: truedefine role ZI_TRAVEL { grant select on ZI_Travel where ( AgencyID ) = aspect pfcg_auth( ZTRAVEL, AGENCY, ACTVT = '03' );}Real project scenario
After go-live of a draft-enabled promotion BO, planners complained that their changes "disappeared". Analysis showed two planners editing the same promotion: the BO had an instance ETag but no total ETag, and the draft of planner A was activated over changes planner B had activated minutes earlier. Adding lock master total etag LastChangedAt made Resume/Activate detect the conflict and show "data changed by another user". A second finding in the same audit: the BO had a DCL restricting read by sales org but no authorization master — any user who could see a promotion could also approve it. Instance authorization with AUTHORITY-CHECK on a custom object closed the gap.
Common mistakes
- Draft-enabled BO without total ETag, so concurrent activations overwrite each other.
- Relying on DCL alone and forgetting authorization master for modify operations.
- Designing draft tables by hand instead of generating them from the BDEF.
- Forgetting "with draft" on create-by-association for children.
- Testing only with a developer user who has SAP_ALL-like authorizations.
Best practices
- Use draft with total ETag for all new Fiori transactional apps.
- Combine DCL (read) and authorization master (modify) — always both.
- Use a custom authorization object with the business field (agency, sales org) for instance checks.
- Test locking and authorization with at least two restricted test users.
- Keep draft lifetime and cleanup (draft expiry) in mind for operations.
Interview angle
Questions: "How does draft work in RAP?", "Difference between locking and ETag?", "How do you implement authorization in RAP?"
Strong answer: draft stores work in progress in a draft table until Activate; lock master sets an exclusive lock, ETags detect concurrent changes (instance ETag via If-Match, total ETag for draft). Authorization is split: CDS DCL restricts read access; authorization master with global and instance methods controls create, update, delete and actions. Senior answers describe testing with restricted users and the risk of DCL without modify authorization.
Practice this lesson
Quick check
1. Which mechanism restricts which rows of a RAP BO a user may read?
2. What is the purpose of the total ETag (lock master total etag LastChangedAt) in a draft-enabled BO?
3. What does draft handling provide in a RAP business object?
Interview questions
1. After go-live of a draft-enabled RAP app, users complain that changes "disappear" when two planners work on the same promotion on the same day. How do you analyse and fix it?
Answer it in your own words first, then compare.
2. A procurement request app must let users save incomplete requests and continue days later, while nobody else changes the same request in between. How do you design this in RAP?
Answer it in your own words first, then compare.
Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.
More lessons in this topic
- RAP Basics Part 1: RAP Architecture — Layers, Artifacts and When RAP Fits
- RAP Basics Part 10: EML — Entity Manipulation Language
- RAP Basics Part 2: Data Model Design — Tables, Keys, Administrative Fields and Interface Views
- RAP Basics Part 3: Projection Layer and Metadata Extensions
- RAP Basics Part 4: Implementation Types — Managed, Unmanaged, Additional Save and Unmanaged Save
- RAP Basics Part 5: Root Entity, Child Entity and Composition
- RAP Basics Part 6: Behavior Definition — CRUD, Field Control and Features
- RAP Basics Part 7: Actions, Determinations and Validations — Design Decisions