ABAP Blog Posts
cancel
Showing results for 
Search instead for 
Did you mean: 

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-on

and

if_abap_behv=>mk-off

Conceptually:

%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 = 1000000001

In 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                Instance

The 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_draft

Therefore, %tky allows RAP to distinguish between:

1000000001 + Active

and:

1000000001 + Draft

This 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_HEADER

with fields such as:

BillId
BillDate
BillType
Currency
CustomerId
NetAmount
SalesOrg

The Business Object is draft-enabled.

We want to implement an action called:

copyBillingDocument

The 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-on

the 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-on

This 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-off

For 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
       |
       +---- Active

7. Implementing the Copy Action

Now let's move to a more realistic scenario.

We create an action:

copyBillingDocument

The 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_draft

Let's break it down.

The action receives the requested draft state through:

%param-%is_draft

The implementation then forwards this value to the CREATE request:

%is_draft

So the flow is:

Action Parameter
      |
      v
%param-%is_draft
      |
      v
Create Structure
      |
      v
%is_draft
      |
      v
RAP Runtime

This 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_CLASSRUN

and 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-off

inside %tky identifies the source instance as active.

And:

%param-%is_draft = if_abap_behv=>mk-on

passes the requested draft state to the action.

Conceptually:

Source
Active
  |
  |
  | copyBillingDocument
  |
  v
New Instance
Draft

10. 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 Target

11. 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:

%tky

which 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_draft

with:

%param-%is_draft

They can represent different parts of the operation.

Conceptually:

                 Action
                   |
          +--------+--------+
          |                 |
          v                 v
     Source State       Target State
          |                 |
       %tky              CREATE
          |                 |
     %is_draft          %is_draft

This 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  = Active

We execute:

%tky = VALUE #(
  %key-BillId = '1000000001'
  %is_draft   = if_abap_behv=>mk-off
)

and request:

%param-%is_draft =
  if_abap_behv=>mk-on

The conceptual flow is:

             Active
               |
               |
               | Action
               |
               v
             Draft

The source and target therefore have different transactional states.

13. Draft Source and Draft Target

Now consider:

Source = Draft
Target = Draft

The 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-on

Conceptually:

             Draft
               |
               |
               | Action
               |
               v
             Draft

14. 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-off

Conceptually:

             Active
                |
                |
                | Action
                |
                v
             Active

The 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
ActiveActiveOFFOFF
ActiveDraftOFFON
DraftDraftONON
DraftActiveONOFF

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
Active

The 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
Active

Activation is a RAP draft lifecycle operation.

Simply thinking of activation as:

%is_draft = if_abap_behv=>mk-off

does 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
Amount

It 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 = 1000000001

does 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 Information

Mistake 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 ON

And when we use %tky:

                    %tky
                      |
             +--------+--------+
             |                 |
          Business Key      %is_draft

Therefore, whenever you see:

%tky

in 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-on

represents the draft context, while:

if_abap_behv=>mk-off

represents 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       Active

Once 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.

3 Comments
Atul_Joshi85
Active Contributor

Fantastic deep dive! This is one of the clearest explanations I’ve seen on how RAP handles Is Draft during instance creation. The step‑by‑step breakdown really helps demystify what’s happening behind the scenes, especially for developers who often struggle with draft behavior in more complex BO scenarios. Your examples make the lifecycle transitions easy to follow, and the emphasis on understanding the framework rather than just the syntax is spot‑on. Thanks for putting together such a practical and insightful walkthrough — this will definitely help many of us build more predictable and stable RAP applications.

Bikash_R
Participant

Thank you @Atul_Joshi85, for the thoughtful feedback. I’m glad you found the explanation clear and useful. I truly appreciate your kind words and support

SachinArtani
Active Participant

Thanks for sharing

Labels in this area