Introduction
The ABAP RESTful Application Programming Model (RAP) provides a built-in draft mechanism that allows users to work with business data before it becomes active.
In a draft-enabled RAP Business Object, an instance can exist in two different transactional states:
- Active instance – the business data has been activated and belongs to the active persistence.
- Draft instance – the business data is currently being created or edited and has not yet been activated.
When a RAP application is consumed through Fiori Elements, most of the draft processing is handled automatically by the RAP framework.
However, the situation becomes more interesting when we work directly with EML (Entity Manipulation Language).
While implementing actions, reads, creates, determinations, validations, or other behavior logic, we may encounter a special component called: %is_draft
This component is part of the BDEF-derived types used by RAP and helps identify whether a transactional instance represents a draft or an active instance.
In this blog, we will understand the role of %is_draft, its relationship with %tky, and how draft and active instances are addressed while working with EML.
1. What is %is_draft?
%is_draft is a technical component provided by the RAP framework for draft-enabled Business Objects.
Its primary purpose is to indicate whether the transactional instance being addressed is a draft or an active instance.
The two possible values are:
if_abap_behv=>mk-onand
if_abap_behv=>mk-offConceptually:
%is_draft = if_abap_behv=>mk-on
|
v
Draft Instance
%is_draft = if_abap_behv=>mk-off
|
v
Active Instance Therefore, whenever we see %is_draft in an EML structure, we should think of it as the technical indicator that helps RAP distinguish between the draft and active transactional instances.
2. Why Do We Need %is_draft?
Consider a Billing Document with the following business key:
Billing Document = 1000000001In a draft-enabled RAP Business Object, the framework can have an active version and a draft version associated with the same business object.
Conceptually:
Billing Document
1000000001
|
+----------+----------+
| |
v v
Active Draft
Instance InstanceThe business key alone is not sufficient to describe the complete transactional identity.
RAP therefore needs additional information to determine which version of the instance is being addressed.
This is where %is_draft becomes important.
3. %is_draft and %tky
One of the most important concepts to understand is the relationship between %is_draft and %tky.
For a draft-enabled Business Object, %tky represents the transactional key.
The transactional key contains the business key together with the draft information.
For example, conceptually:
%tky
|
+-- Business Key
|
+-- %is_draftTherefore, %tky allows RAP to distinguish between:
1000000001 + Activeand:
1000000001 + DraftThis is why %tky is commonly used in RAP behavior implementations when referring to instances.
For example:
%tky = VALUE #(
%key-BillId = '1000000001'
%is_draft = if_abap_behv=>mk-on
)Here, the transactional key identifies the draft version of the Billing Document.
4. A Simple Billing Document Scenario
Let's use a simple Billing Document Business Object throughout this example.
Assume we have the following entity:
ZBR_T_BILL_HEADERwith fields such as:
BillId
BillDate
BillType
Currency
CustomerId
NetAmount
SalesOrgThe Business Object is draft-enabled.
We want to implement an action called:
copyBillingDocumentThe requirement is:
Copy an existing Billing Document and create a new Billing Document while allowing the caller to specify the required draft context.
The basic process is:
Existing Billing Document
|
|
| copyBillingDocument
|
v
New Billing Document
5. Creating a Draft Instance Using EML
Let's first look at a simple CREATE operation.
When the EML request contains:
%is_draft = if_abap_behv=>mk-onthe request identifies the instance as a draft instance.
Example:
MODIFY ENTITIES OF zbrt_i_bill_header
ENTITY zbrt_i_bill_header
CREATE FIELDS
(
BillId
BillDate
BillType
Currency
CustomerId
NetAmount
SalesOrg
)
WITH VALUE #(
(
%is_draft = if_abap_behv=>mk-on
BillId = '1000000005'
BillDate = cl_abap_context_info=>get_system_date( )
BillType = 'F2'
Currency = 'INR'
CustomerId = '100001'
NetAmount = '5000'
SalesOrg = '1000'
)
)
MAPPED DATA(mapped)
FAILED DATA(failed)
REPORTED DATA(reported).The important part is:
%is_draft = if_abap_behv=>mk-onThis indicates the draft context for the create request.
6. Identifying an Active Instance
Now consider an active instance.
The draft indicator is:
%is_draft = if_abap_behv=>mk-offFor example:
%tky = VALUE #(
%key-BillId = '1000000001'
%is_draft = if_abap_behv=>mk-off
)This identifies the active transactional instance.
Therefore:
%is_draft = ON
|
+---- Draft
%is_draft = OFF
|
+---- Active7. Implementing the Copy Action
Now let's move to a more realistic scenario.
We create an action:
copyBillingDocumentThe action receives the source Billing Document and a parameter indicating the requested draft state for the newly created document.
The action implementation reads the source instance and prepares the data for a new instance.
Example implementation:
METHOD copyBillingDocument.
DATA:
lt_billingdocuments TYPE TABLE FOR CREATE
zbrt_i_bill_header\zbrt_i_bill_header,
lv_billingdoc TYPE c LENGTH 10.
"Get the highest existing Billing Document number
SELECT FROM zbrt_i_bill_header
FIELDS MAX( BillId )
INTO @lv_billingdoc.
"Generate the next Billing Document number
lv_billingdoc = lv_billingdoc + 1.
"Read the source Billing Document
READ ENTITIES OF zbrt_i_bill_header IN LOCAL MODE
ENTITY zbrt_i_bill_header
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_billdoc).
LOOP AT lt_billdoc ASSIGNING FIELD-SYMBOL(<ls_billdoc>).
APPEND VALUE #(
%cid = keys[
KEY entity
%key = <ls_billdoc>-%key
]-%cid
%is_draft = keys[
KEY entity
%key = <ls_billdoc>-%key
]-%param-%is_draft
%data = CORRESPONDING #(
<ls_billdoc>
EXCEPT BillId )
)
TO lt_billingdocuments
ASSIGNING FIELD-SYMBOL(<ls_new_bill>).
"Set new Billing Document number
<ls_new_bill>-BillId =
CONV #( lv_billingdoc ).
"Set new Billing Date
<ls_new_bill>-BillDate =
cl_abap_context_info=>get_system_date( ).
ENDLOOP.
"Create the new Billing Document
MODIFY ENTITIES OF zbrt_i_bill_header IN LOCAL MODE
ENTITY zbrt_i_bill_header
CREATE
FIELDS
(
BillId
BillDate
BillType
Currency
CustomerId
NetAmount
SalesOrg
)
WITH lt_billingdocuments
MAPPED DATA(mapped_create).
"Return created instances
mapped-zbrt_i_bill_header =
mapped_create-zbrt_i_bill_header.
ENDMETHOD.8. Understanding the Important Line
The most important line in the above implementation is:
%is_draft = keys[
KEY entity
%key = <ls_billdoc>-%key
]-%param-%is_draftLet's break it down.
The action receives the requested draft state through:
%param-%is_draftThe implementation then forwards this value to the CREATE request:
%is_draftSo the flow is:
Action Parameter
|
v
%param-%is_draft
|
v
Create Structure
|
v
%is_draft
|
v
RAP RuntimeThis allows the action implementation to pass the requested draft context to the subsequent EML CREATE operation.
9. Executing the Action Using EML
To test the action, we can create an ABAP class implementing:
IF_OO_ADT_CLASSRUNand execute the EML from the class.
The action can be called like this:
MODIFY ENTITIES OF zbrt_i_bill_header
ENTITY zbrt_i_bill_header
EXECUTE copyBillingDocument
FROM VALUE #(
(
%cid = 'COPY_001'
%tky = VALUE #(
%key-BillId = '1000000001'
%is_draft = if_abap_behv=>mk-off
)
%param-%is_draft =
if_abap_behv=>mk-on
)
)
MAPPED DATA(mapped)
FAILED DATA(failed)
REPORTED DATA(reported).Here:
%is_draft = if_abap_behv=>mk-offinside %tky identifies the source instance as active.
And:
%param-%is_draft = if_abap_behv=>mk-onpasses the requested draft state to the action.
Conceptually:
Source
Active
|
|
| copyBillingDocument
|
v
New Instance
Draft10. Scenario: Draft Source
Now consider that the source Billing Document itself is a draft.
The transactional key should identify the draft instance:
%tky = VALUE #(
%key-BillId = '1000000002'
%is_draft = if_abap_behv=>mk-on
)For example:
MODIFY ENTITIES OF zbrt_i_bill_header
ENTITY zbrt_i_bill_header
EXECUTE copyBillingDocument
FROM VALUE #(
(
%cid = 'COPY_002'
%tky = VALUE #(
%key-BillId = '1000000002'
%is_draft = if_abap_behv=>mk-on
)
%param-%is_draft =
if_abap_behv=>mk-on
)
)
MAPPED DATA(mapped)
FAILED DATA(failed)
REPORTED DATA(reported).Here the source transactional instance is a draft.
The requested target context is also draft.
The conceptual flow is:
Draft Source
|
|
| copyBillingDocument
|
v
Draft Target11. Understanding the Difference Between Source and Target
This is an important point when working with actions.
There are two different questions:
Question 1: Which instance should the action operate on?
This is determined by the transactional key:
%tkywhich contains the instance key and draft information.
Question 2: What should happen to the newly created instance?
This is controlled by the data passed to the CREATE operation, including the draft context where applicable.
Therefore, we should not confuse:
%tky-%is_draftwith:
%param-%is_draftThey can represent different parts of the operation.
Conceptually:
Action
|
+--------+--------+
| |
v v
Source State Target State
| |
%tky CREATE
| |
%is_draft %is_draftThis distinction is particularly useful in copy-by-action scenarios.
12. Active Source and Draft Target
Let's take another example.
Suppose:
Source Billing Document
BillId = 1000000001
State = ActiveWe execute:
%tky = VALUE #(
%key-BillId = '1000000001'
%is_draft = if_abap_behv=>mk-off
)and request:
%param-%is_draft =
if_abap_behv=>mk-onThe conceptual flow is:
Active
|
|
| Action
|
v
DraftThe source and target therefore have different transactional states.
13. Draft Source and Draft Target
Now consider:
Source = Draft
Target = DraftThe source key is:
%tky = VALUE #(
%key-BillId = '1000000002'
%is_draft = if_abap_behv=>mk-on
)and the requested target context is:
%param-%is_draft =
if_abap_behv=>mk-onConceptually:
Draft
|
|
| Action
|
v
Draft14. Active Source and Active Target
The same concept can be applied when both the source and target are active.
The source transactional key would identify the active instance:
%tky = VALUE #(
%key-BillId = '1000000001'
%is_draft = if_abap_behv=>mk-off
)and the requested target context would be active:
%param-%is_draft =
if_abap_behv=>mk-offConceptually:
Active
|
|
| Action
|
v
ActiveThe important point is that the source and target contexts are separate considerations.
15. Scenario Summary
The different combinations can be summarized as follows:
Source State Target State Source %is_draft Target %is_draft| Active | Active | OFF | OFF |
| Active | Draft | OFF | ON |
| Draft | Draft | ON | ON |
| Draft | Active | ON | OFF |
This table is useful when debugging EML requests involving draft-enabled Business Objects.
16. Using %tky in Behavior Implementations
When implementing RAP behavior methods, we frequently receive keys in the keys parameter.
For example:
METHOD someAction.
READ ENTITIES OF zbrt_i_bill_header IN LOCAL MODE
ENTITY zbrt_i_bill_header
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_billdoc).
ENDMETHOD.The keys passed to the method represent the transactional instances on which the operation is being performed.
For draft-enabled objects, %tky carries the required draft information.
Therefore, developers should avoid unnecessarily reconstructing the transactional identity manually.
Using the RAP-generated key structures helps the implementation remain aligned with the framework's draft handling.
17. Draft Handling Through Fiori Elements
When a draft-enabled RAP Business Object is consumed through Fiori Elements, developers normally do not have to manually set %is_draft.
For example, the user might perform:
Create
|
v
Draft
|
v
Edit Data
|
v
Save
|
v
Activate
|
v
ActiveThe RAP framework manages the corresponding draft lifecycle.
The developer mainly needs to understand %is_draft when working with lower-level RAP operations such as:
- EML
- Behavior implementations
- Actions
- Determinations
- Validations
- Custom transactional logic
18. Important Difference Between Draft State and Activation
One important point should be kept in mind.
%is_draft indicates the draft context of an instance involved in a transactional operation.
It should not be treated as a replacement for the complete RAP draft lifecycle.
For example:
Draft
|
| Activate
v
ActiveActivation is a RAP draft lifecycle operation.
Simply thinking of activation as:
%is_draft = if_abap_behv=>mk-offdoes not by itself represent the complete activation process.
The RAP framework performs the required processing for the transition between draft and active states.
Therefore, %is_draft should be understood as an instance-state indicator, not as an instruction to manually move data between draft and active persistence.
19. Common Mistakes
Mistake 1: Treating %is_draft as an Application Field
%is_draft is not a normal business field such as:
BillId
Customer
Currency
AmountIt is a technical component generated by RAP for transactional processing.
Mistake 2: Using Only the Business Key
For a draft-enabled object, the application key alone may not be enough to describe the transactional instance.
For example:
BillId = 1000000001does not by itself communicate whether the request refers to the draft or active version.
The transactional key carries this information.
Mistake 3: Confusing %key and %tky
%key represents the business key.
%tky represents the transactional key.
For draft-enabled objects, %tky also contains the draft information.
Conceptually:
%key
|
+-- Business Key
%tky
|
+-- Business Key
|
+-- Draft InformationMistake 4: Assuming the UI Requires Manual Draft Handling
In a normal Fiori Elements application, the RAP framework handles most draft processing automatically.
Manual handling becomes relevant mainly when implementing custom EML or behavior logic.
Mistake 5: Directly Manipulating Draft Persistence
The draft persistence is managed by the RAP framework.
Application logic should use RAP behavior and EML rather than directly inserting, updating, or deleting records in the draft table.
20. A Simple Mental Model
The easiest way to remember %is_draft is:
RAP Transaction
|
+--------+--------+
| |
v v
Active Draft
| |
v v
%is_draft OFF %is_draft ONAnd when we use %tky:
%tky
|
+--------+--------+
| |
Business Key %is_draftTherefore, whenever you see:
%tkyin a draft-enabled RAP Business Object, remember that the transactional identity also carries the information required to distinguish the draft and active instance.
21. Key Takeaways
The most important points from this article are:
1. %is_draft is a RAP technical indicator
It identifies the draft context of a transactional instance.
2. ON represents draft and OFF represents active
if_abap_behv=>mk-onrepresents the draft context, while:
if_abap_behv=>mk-offrepresents the active context.
3. %is_draft is related to %tky
For draft-enabled Business Objects, the transactional key contains the draft information.
4. %tky is important in behavior implementations
It helps the RAP runtime identify the correct transactional instance.
5. Actions can operate on draft or active instances
The transactional key determines the source instance being addressed.
6. Source and target state are separate concepts
In a copy/create-by-action scenario, the source can be active while the target is draft, or both can be draft, depending on the implementation and RAP lifecycle rules.
7. Fiori Elements hides much of this complexity
When using standard draft-enabled Fiori Elements applications, RAP manages most of the draft lifecycle automatically.
8. %is_draft is not the same as activation
It identifies the transactional state; it should not be considered a replacement for RAP's draft activation lifecycle.
Conclusion
Draft handling is one of the powerful features of SAP RAP, but it can initially be confusing when we start working with EML and behavior implementations.
The %is_draft component provides an important piece of information to the RAP runtime by distinguishing draft and active transactional instances.
The relationship can be remembered as:
Draft-enabled RAP BO
|
v
%tky
|
+--------+--------+
| |
%is_draft Business Key
|
+-----+-----+
| |
ON OFF
| |
Draft ActiveOnce this relationship is clear, it becomes much easier to understand why %tky is used extensively in RAP behavior implementations and how EML identifies the correct transactional instance.
Rather than thinking of %is_draft as just a simple Boolean flag, it is better to view it as part of RAP's transactional identity and draft-processing mechanism.
That understanding becomes especially valuable when implementing custom actions, EML-based operations, determinations, validations, and other advanced RAP scenarios.