Skip to Content
Technical Articles

ABAP on SAP Cloud platform – ABAP RESTful Programming Model (RAP) for beginners with CRUD example

Hello Guys,

In this blog we will learn new programming model RAP in detail with an example, I would recommend to go through the theory as well before you start coding to understand RAP basics.I would like to thank my colleagues in SAP specially Kailash Satapathy and Gaurav Kumar for helping me in writing this blog.

Prerequisite: 

Concepts of Core Data Services(CDS) and annotations.

Lets Start ūüôā

¬†RESTful ABAP Programming Model (RAP): The term RESTful ABAP Programming Model (RAP) is chosen to reflect its orientation towards a ‚Äústateless‚ÄĚ REST architecture.

We will start with ABAP evolution over the years: –

Evolution of the ABAP Programming Model

We kick started our ABAP WORLD with classical ABAP programming using reports and module pool programs, then we moved to BSP/Webdynpro with FPM (for UI harmonization), then slowly shifted from ERP style developments to S/4 HANA model developments where our major programming consists of artifacts like CDS, BOPF, GW and Fiori.

ABAP Programming model for SAP Fiori (Current best practice) : –

This development model usually consists of CDS view, BOPF and GW where CDS is tightly coupled with BOPF and GW (using RDS Mapping or using @OData.Publish annotation).

Note: Issue with this model is flow is not well defined

Future Direction – New Programming Model (ABAP Restful Programming Model)

RESTful ABAP Programming model in detail:

The ABAP RESTful programming model defines the architecture for efficient end-to-end development of intrinsically SAP HANA-optimized OData services (such as Fiori apps) in¬†SAP Cloud Platform ABAP Environment. It supports the development of all types of Fiori applications as well as A2X services. It is based on technologies and frameworks such as Core Data Services (CDS) for defining semantically rich data models and a service model infrastructure for creating OData services with bindings to an OData protocol and ABAP-based application services for custom logic and SAPUI5-based user interfaces ‚Äď as shown in the figure below

Understanding Concepts

  1. Business Object

A business object (BO) is a common term to represent a real-world artifact in enterprise application development such as the Product, the Travel, or the SalesOrder. In general, a business object contains several nodes such as Items and and common transactional operations such as for creating, updating and deleting data and additional application-specific operations, such as Approve in a SalesOrder business object.

From a formal point of view, a business object is characterized by

  • a structure,
  • a behavior and
  • the corresponding runtime implementation.

See the figure for more details.

 

1.1 Structure of a Business Object

From structural aspect, a business object consists of a tree of nodes (SalesOrder, Items, ScheduleLines) where the nodes are linked by means of a special kind of associations, the compositions. A composition is specialized association that defines a whole-part relationship. A composite part only exists together with its parent entity (whole).

Each node of this composition tree is an element that is modelled with a CDS entity. The root entity is of particular importance: This is considered in the source code of the CDS data definition with the keyword¬†ROOT. The root entity serves as a representation of the business object and defines the top node in a business object’s structure.

1.2 Behavior of a Business Object

Each entity of the business object can offer the standard CUD operations create(), update() and delete(). In addition, each entity can also offer specific operations with a dedicated input and output structure which are called actions. The offered CUD operations, actions as well some behavior-relevant properties, such as lock dependencies between the parent and child entities are defined in the behavior definition artifact.

A behavior definition always refers to a CDS data model. As shown in the figure below, a behavior definition relies directly on the CDS root entity. One behavior definition refers exactly to one root entity and one CDS root entity has at most one behavior definition (a 0..1 relationship), which also handles all included child entities.

1.3 Business Object’s Runtime Implementation

The business object runtime mainly consists of two parts: The first part is the interaction phase where a consumer calls the business object operations to change data and read instances with or without the transactional changes. The business object runtime keeps the changes in its internal transactional buffer which represents the state of the instance data. This transactional buffer is always required for a business object. After all changes were performed, the data can be persisted. This is realized with the save sequence.

Business object runtime in detail

Interaction phase have different steps which we segregated as Modify, Read and Lock. Save sequence phase will have steps like Finalise, check_before_save, adjust_numbers and save.

Implementations can be classified as Unmanaged, Managed and Managed with save.

Currently supported implementation is Unmanaged. Managed and Managed with save implementations will come in future releases.

  1. Business Service

The ABAP development platform can act in the roles of service provider and service consumer, such as SAP Fiori UI client.

In the context of the ABAP RESTful programming model, a business service is RESTful service which can be called by a consumer. It is defined by exposing data models and behavior models. It consists of a Service definition and a Service binding which are illustrated in the figure below: –

 

The Service Definition is a projection of the data model and the related behavior to be exposed, whereas the Service Binding implements a specific protocol and the kind of service to be offered for a consumer. This separation allows the data models and service definitions to be integrated into various protocols without any re-implementation.

2.1 Service Definition

 A service definition represents the service model that is generically derived from the underlying CDS-based data model.

Example :-

DEFINE SERVICE service_definition_name

{

EXPOSE cds_entity_1 [AS alias_1];

EXPOSE cds_entity_2 [AS alias_2];

EXPOSE …

EXPOSE cds_entity_m [AS alias_m];

}

2.2 Service Binding

 The business service binding (short form: service binding) is an ABAP Repository object used to bind a service definition to a client-server communication protocol such as OData.

Relationship between the Data Model, the Service Definition and Service Binding

Let’s learn RAP with a CRUD Example.

Here we will go with the Sales Order CRUD Example.

¬†For testing purpose, I have created Sales Order Header table ‚Äď ZSSK_VBAK and Sales Order Item¬† table ¬†¬†‚Äď ZSSK_VBAP

ZSSK_VBAK

 

ZSSK_VBAP

We have 3 steps to implement here.

  1. Provide the CDS Data Model with Business Object Structure
  2. Defining and Implementing Behavior of the Business Object.
  3. Defining Business Service for Fiori UI.

 

  1. Provide the CDS Data Model with Business Object Structure

 

 Here we will create CDS view for Business object using Composition and associations to sub nodes.

¬†Code snippet for Sales Order Header CDS view: –

@AbapCatalog.sqlViewName: ‘ZSSKSOHDR’

@AbapCatalog.compiler.compareFilter: true

@AbapCatalog.preserveKey: true

@AccessControl.authorizationCheck: #NOT_REQUIRED

@EndUserText.label: ‘Sales Order Header’

@UI: {

headerInfo: {

typeName: ‘Sales Order’,

typeNamePlural: ‘Sales Orders’,

title: { type: #STANDARD, value: ‘vbeln’ }

}

}

@ObjectModel.semanticKey: [‘vbeln’]

@ObjectModel.representativeKey: ‘vbeln’

define root view Zssk_SoHeader as select from zssk_vbak as SOHeader

composition [0..*] of Zssk_SoItem as _SOItem

{

@UI.facet: [

{

id: ‘GeneralData’,

type: #COLLECTION,

position: 10,

label: ‘Sales Order Header’

},

{

type: #FIELDGROUP_REFERENCE,

position: 10,

targetQualifier: ‘GeneralData1’,

parentId: ‘GeneralData’,

isSummary: true,

isPartOfPreview: true

},

{

type: #FIELDGROUP_REFERENCE,

position: 20,

targetQualifier: ‘GeneralData2’,

parentId: ‘GeneralData’,

isSummary: true,

isPartOfPreview: true

},

{

id: ‘SOItem’,

purpose: #STANDARD,

type: #LINEITEM_REFERENCE,

label: ‘Sales Order Item’,

position: 10,

targetElement: ‘_SOItem’

}

]

@UI: {

lineItem: [ { position: 10, importance: #HIGH } ],

selectionField: [{position: 10 }],

fieldGroup: [{qualifier: ‘GeneralData1’,position: 10,importance: #HIGH }]

}

key   SOHeader.vbeln,

@UI: {

lineItem: [ { position: 20, importance: #HIGH } ],

selectionField: [{position: 20 }],

fieldGroup: [{qualifier: ‘GeneralData2’,position: 10,importance: #HIGH }]

}

SOHeader.erdat,

@UI: {

lineItem: [ { position: 30, importance: #HIGH } ],

fieldGroup: [{qualifier: ‘GeneralData2’,position: 20,importance: #HIGH }]

}

SOHeader.ernam,

@UI: {

lineItem: [ { position: 40, importance: #HIGH } ],

fieldGroup: [{qualifier: ‘GeneralData1’,position: 20,importance: #HIGH }]

}

SOHeader.vkorg,

@UI: {

lineItem: [ { position: 50, importance: #HIGH } ],

fieldGroup: [{qualifier: ‘GeneralData1’,position: 30,importance: #HIGH }]

}

SOHeader.vtweg,

@UI: {

lineItem: [ { position: 60, importance: #HIGH } ],

fieldGroup: [{qualifier: ‘GeneralData1’,position: 40,importance: #HIGH }]

}

SOHeader.spart,

//For action Set Favourite in UI

@UI.lineItem: [{ type: #FOR_ACTION,dataAction: ‘set_favourite’,label: ‘Set Favourite’ },

{position: 15, importance: #HIGH}]

@EndUserText.label: ‘Favourite’

SOHeader.favourite,

SOHeader.lastchangedby,

SOHeader.lastchangedat,

/*Association*/

_SOItem

}

 

Code Snipper for Sales Order Item CDS view :-

@AbapCatalog.sqlViewName: ‘ZSSKSOITM’

@AbapCatalog.compiler.compareFilter: true

@AbapCatalog.preserveKey: true

@AccessControl.authorizationCheck: #CHECK

@EndUserText.label: ‘Sales Order Item’

@ObjectModel.representativeKey: [‘vbeln’,’posnr’]

define view Zssk_SoItem as select from zssk_vbap as SOItem

association to parent Zssk_SoHeader as _SOHeader on(

$projection.vbeln = _SOHeader.vbeln

)

{

@UI.facet: [

{type: #COLLECTION, position: 10, id: ‘SoItem’, label: ‘Sales Order Item’},

{type: #FIELDGROUP_REFERENCE, position: 10, targetQualifier: ‘SoItem1’,parentId: ‘SoItem’, isSummary: true, isPartOfPreview: true},

{type: #FIELDGROUP_REFERENCE, position: 20, targetQualifier: ‘SoItem2’,parentId: ‘SoItem’, isSummary: true, isPartOfPreview: true}

]

@UI: {

lineItem: [ { position: 10, importance: #HIGH } ],

fieldGroup: [{qualifier: ‘SoItem1’,position: 10,importance: #HIGH }]

}

key  SOItem.vbeln,

@UI: {

lineItem: [ { position: 20, importance: #HIGH } ],

fieldGroup: [{qualifier: ‘SoItem1’,position: 20,importance: #HIGH }]

}

key  SOItem.posnr,

@UI: {

lineItem: [ { position: 30, importance: #HIGH } ],

fieldGroup: [{qualifier: ‘SoItem2’,position: 10,importance: #HIGH }]

}

SOItem.matnr,

@UI: {

lineItem: [ { position: 40, importance: #HIGH } ],

fieldGroup: [{qualifier: ‘SoItem2’,position: 20,importance: #HIGH }]

}

SOItem.zmeng,

SOItem.meins,

/*Association*/

_SOHeader

}

 

  1. Defining and Implementing Behavior of the Business Object

Here we will create Behavior definition and implementation for BO.

Right click on CDS view Zssk_SoHeader and create New Behavior definition

Code Snippet for Behavior Definition: –

implementation unmanaged;

define behavior for Zssk_SoHeader alias SOHeader

{

create;

update;

delete;

action set_favourite result [1] $self;

association  _SOItem { create; }

}

define behavior for Zssk_SoItem alias  SOItem

{

create;

update;

delete;

}

We can implement e-tag and locking also in behavior definition: –

 

After this step, we will create Behavior Implementation, right click Behavior definition and opt New Behavior Implementation.

 

Note: The moment you create a new Behavior implementation, local classes will get generated with Behavior class definition for Interaction Phase and Save Sequence Phase (Please refer topic Business object runtime in detail)

 

We will write our logic in respective class, to make it simple I am putting code only in Modify Method in lcl_handler class.

Note : Ideally scenario will be like entries from the UI will be putting into the transaction buffer by Interaction phase( modify(), read() and lock() methods) with a proper locking mechanism and Save Sequence phase( finalize(),check_before_save(),adjust_numbers() and save() methods) will take care of database commit and rollback part with proper validation.

 

Code Snippet for Modify method to update Sales Order Header and Item tables.

Here I am using INSERT,UPDATE and DELETE statements for CRUD operations to make it simple, but in ideal scenarios we will be using BAPI/APIs for CRUD operations.

CLASS lcl_handler DEFINITION INHERITING FROM cl_abap_behavior_handler.

PRIVATE SECTION.

DATA : lt_soheader TYPE TABLE  OF Zssk_vbak,

lt_soitem     TYPE TABLE OF Zssk_vbap,

ls_vbap       TYPE Zssk_vbap,

lt_fields       TYPE TABLE OF dfies.

 

METHODS modify FOR BEHAVIOR IMPORTING

For Header table

it_set_fav FOR ACTION soheader~set_favourite RESULT et_soheader

it_soheader_create    FOR CREATE soheader

it_soheader_update   FOR UPDATE soheader

it_soheader_delete    FOR DELETE soheader

” For Item table

it_soheader_soitem_create     FOR CREATE soheader\_soitem

it_soitem_create    FOR CREATE soitem

it_soitem_update    FOR UPDATE soitem

it_soitem_delete    FOR DELETE soitem.

ENDCLASS.

CLASS lcl_handler IMPLEMENTATION.

METHOD modify.

/**************************Action Set Favourite************************/

IF it_set_fav IS NOT INITIAL.

DATA(ls_fav_so) = it_set_fav[ 1 ].

UPDATE zssk_vbak SET favourite = ‘X’ WHERE vbeln = ls_fav_so-vbeln.

IF sy-subrc EQ 0.

SELECT * FROM zssk_vbak INTO CORRESPONDING FIELDS OF TABLE et_soheader WHERE vbeln = ls_fav_so-vbeln.

ENDIF.

ENDIF.

/***************************************************************************/

/* CRUD Operations  for Header table */

/***************************Create****************************************/

IF it_soheader_create IS NOT INITIAL.

MOVE-CORRESPONDING   it_soheader_create TO lt_soheader.

INSERT  zssk_vbak FROM TABLE lt_soheader.

ENDIF.

/*************************************************************************/

/***************************Update*************************************/

IF it_soheader_update IS NOT INITIAL.

CALL FUNCTION ‘DDIF_FIELDINFO_GET’

EXPORTING

tabname¬†¬†¬†¬†¬†¬†¬† = ‘ZSSK_VBAK’

TABLES

dfies_tab      = lt_fields

EXCEPTIONS

not_found      = 1

internal_error = 2

OTHERS         = 3.

IF sy-subrc <> 0.

ENDIF.

DATA(ls_hdr) = it_soheader_update[ 1 ].

SELECT SINGLE *

FROM zssk_vbak

INTO @DATA(ls_vbak)

WHERE vbeln = @ls_hdr-vbeln.

LOOP AT lt_fields ASSIGNING FIELD-SYMBOL(<fs_field>).

ASSIGN COMPONENT <fs_field>-fieldname OF STRUCTURE ls_hdr TO FIELD-SYMBOL(<fs_target>).

IF <fs_target> IS ASSIGNED AND <fs_target> IS NOT INITIAL.

ASSIGN COMPONENT <fs_field>-fieldname OF STRUCTURE ls_vbak TO FIELD-SYMBOL(<fs_source>).

<fs_source> = <fs_target>.

ENDIF.

ENDLOOP.

APPEND ls_vbak TO lt_soheader.

UPDATE  zssk_vbak  FROM TABLE lt_soheader.

ENDIF.

/*************************************************************************/

/****************************Delete*************************************/

IF it_soheader_delete IS NOT INITIAL.

MOVE-CORRESPONDING   it_soheader_delete TO lt_soheader.

DELETE  zssk_vbak FROM TABLE lt_soheader.

IF sy-subrc EQ 0.

DATA(lv_vbeln) = lt_soheader[ 1 ]-vbeln.

IF  lv_vbeln IS NOT INITIAL.

DELETE FROM zssk_vbap WHERE vbeln EQ lv_vbeln.

ENDIF.

ENDIF.

ENDIF.

/*************************************************************************/

/* CRUD Operations  for Item table */

/***************************Create****************************************/

IF  it_soheader_soitem_create IS NOT INITIAL.

READ TABLE it_soheader_soitem_create INTO DATA(ls_item) INDEX 1.

IF sy-subrc EQ 0.

MOVE-CORRESPONDING ls_item-%target TO lt_soitem.

ENDIF.

IF lt_soitem IS NOT INITIAL.

INSERT  zssk_vbap FROM TABLE lt_soitem.

ENDIF.

ENDIF.

IF it_soitem_create IS NOT INITIAL.

MOVE-CORRESPONDING   it_soitem_create TO lt_soitem.

INSERT  zssk_vbap FROM TABLE lt_soitem.

ENDIF.

/*************************************************************************/

/***************************Update*************************************/

IF it_soitem_update IS NOT INITIAL.

CALL FUNCTION ‘DDIF_FIELDINFO_GET’

EXPORTING

tabname¬†¬†¬†¬†¬†¬†¬† = ‘ZSSK_VBAP’

TABLES

dfies_tab      = lt_fields

EXCEPTIONS

not_found      = 1

internal_error = 2

OTHERS         = 3.

IF sy-subrc <> 0.

ENDIF.

DATA(ls_itm) = it_soitem_update[ 1 ].

SELECT  *

FROM zssk_vbap

INTO TABLE @DATA(lt_vbap)

WHERE vbeln = @ls_itm-vbeln.

CLEAR ls_itm.

LOOP AT  it_soitem_update INTO ls_itm.

READ TABLE lt_vbap INTO DATA(ls_vbap) WITH KEY vbeln = ls_itm-vbeln posnr = ls_itm-posnr.

IF sy-subrc EQ 0.

LOOP AT lt_fields ASSIGNING FIELD-SYMBOL(<fs_itm_field>).

ASSIGN COMPONENT <fs_itm_field>-fieldname OF STRUCTURE ls_itm TO FIELD-SYMBOL(<fs_itm_target>).

IF <fs_itm_target> IS ASSIGNED AND <fs_itm_target> IS NOT INITIAL.

ASSIGN COMPONENT <fs_itm_field>-fieldname OF STRUCTURE ls_vbap TO  FIELD-SYMBOL(<fs_itm_source>).

<fs_itm_source> = <fs_itm_target>.

ENDIF.

ENDLOOP.

ENDIF.

APPEND ls_vbap TO lt_soitem.

CLEAR: ls_vbap,

ls_itm.

ENDLOOP.

UPDATE  zssk_vbap  FROM TABLE lt_soitem.

ENDIF.

/*************************************************************************/

/****************************Delete*************************************/

IF it_soitem_delete IS NOT INITIAL.

MOVE-CORRESPONDING   it_soitem_delete TO lt_soitem.

DELETE  zssk_vbap FROM TABLE lt_soitem.

ENDIF.

/*************************************************************************/

ENDMETHOD.

ENDCLASS.

CLASS lcl_saver DEFINITION INHERITING FROM cl_abap_behavior_saver.

PROTECTED SECTION.

METHODS finalize          REDEFINITION.

METHODS check_before_save REDEFINITION.

METHODS save              REDEFINITION.

ENDCLASS.

 

CLASS lcl_saver IMPLEMENTATION.

METHOD finalize.

ENDMETHOD.

METHOD check_before_save.

ENDMETHOD.

METHOD save.

ENDMETHOD.

ENDCLASS.

 

  1. Defining Business Service for Fiori UI

Here we will create Service definition and Service Binding.

 

 Service Definition.

The service definition is a projection of the data model and the related behavior to be exposed.

Right click your Package->New->other ABAP Repository Object->Business Service->Service Definition

Code Snippet for Service Definition: –

 

 Service Binding

The service binding implements a specific protocol and the kind of service to be offered for a consumer.

Right click your Package->New->other ABAP Repository Object->Business Service->Service Binding.

Give name of Service Binding and service definition name for which binding needs to be created and click on Finish

Click on the button Publish as shown below to publish Odata service locally which makes service ready for consumption

Once we published, we can see published Information on right side.

Click on Service Url to see the Metadata

Right click on SOHeader/SoItem to see the UI Preview

 

APP Preview

This is just a preview and it will be useful to check how the UI looks with annotations implemented in CDS.

 

Note: – We can create proper UI project from Web IDE and map our Service Binding to test this application. Launch Web IDE -> Create Project from template->List Report->Map Service Binding

Our App will look like this :- It will show a list of sales orders.

Once we select the line item, Action ‘Set Favourite’ and CUD operations will be enabled:-

Once we click on the line item, It will go to the respective Sales order item page.

The above steps will guide you on how to create a RAP CRUD application.

Overview: ABAP Restful Programming Model: Development Flow

Steps to remember:-

  1. Model CDS view with proper annotations.( For simplicity I have created only one CDS view for root and then one for Item, but ideally, we will follow like we will create basic views for SO header and Item, then transactional( BO views ) for SO header and Item and then Projection views for SO Header and Item ).
  2. Create a Behavior definition for CDS views. ( Behavior definition for root transactional view and Behavior projection for Projection view )
  3. Create Behavior implementation for Behavior definition.
  4. Create a Service definition.
  5. Create Service Binding and add Service definition name for which binding needs to be created and Publish.
  6. Create WebIde project and map Service binding to it.

Conclusion: This programming model will be the future of ABAP which will be protocol agnostic and the good news is SAP will continue to support the ABAP Programming Model for SAP Fiori beside the ABAP RESTful Programming Model in the future for upwards compatibility reasons.

Hope you find this blog helpful.

 

37 Comments
You must be Logged on to comment or reply to a post.
  • Nice Blog Indeed!

    I believe ‚ÄėService Binding‚Äô and ‚ÄėService Definition‚Äô along with Behaviour Definition is not part of S4 HANA 1809 on Premises as it is giving error to me, may be it is part of Cloud.

     

    Regards,

    Abhijeet

  • Hello Sony Sukumar,

    When I tried with the SCN developer tutorial and created separate CUD methods it works for me but when I put them in one modify method it only works for create and throws dump in Update and delete.

    The dump is related to the model IMO.

    METHOD trigger_appl_model_error_dump.
    DATA(_) = COND i( WHEN mv_aunit_exc_instead_of_dump <> abap_true THEN
    THROW SHORTDUMP cx_sadl_dump_appl_model_error( ix_cause = cause )
    “########################################################################################
    “# !!! ATTENTION !!! #
    “# Processing was deliberately stopped because an application modeling error has been #
    “# detected. Please identify the root cause and contact the application owners: #
    “# Carefully read the “Error Analysis” section of this dump (“Long text” tab in ADT #
    “# or if viewed in SAP GUI (transaction ST22) in “ABAP Developer View”). #
    “# For more detailed information refer to the exception chain contained in the dump. #
    “# Identify the CDS view and/or service implementation classes to route this issue to #
    “# the responsible application component. To facilitate the support incident please #
    “# attach a full export of this dump and a description of your scenario. Thank you! #
    “########################################################################################
    ELSE THROW RESUMABLE cx_sadl_dump_appl_model_error( ix_cause = cause ) ). ” For unit tests only; RESUMABLE allows for 100% coverage.
    ENDMETHOD.

     

    Can you please help ?

    BDL =>

    implementation unmanaged;
    define behavior for YI_BOOKING_xxx implementation in class y_i_booking_xxx
    lock master
    etag LastChangedAt
    {
    field ( mandatory ) CustomerName, DateOfBooking, DateOfTravel, EmailAddress;
    create;
    update;
    delete;
    action set_status result [1] $self;
    }

     

    CDS =>

    @AbapCatalog.sqlViewName: ‘YV_BOOKING_XXX’
    @AbapCatalog.compiler.compareFilter: true
    @AbapCatalog.preserveKey: true
    @AccessControl.authorizationCheck: #CHECK
    @EndUserText.label: ‘View on booking information’
    @Search.searchable: true

    @UI: {
    headerInfo: {
    typeName: ‘Booking’,
    typeNamePlural: ‘Bookings’,
    title: { type: #STANDARD, value: ‘Booking’ }
    }
    }

    define root view YI_BOOKING_xxx
    as select from ypsb_booking_xxx as Booking
    association [0..1] to I_Country as _Country on $projection.country = _Country.Country
    association [0..1] to I_Currency as _Currency on $projection.CurrencyCode = _Currency.Currency
    {

    @UI.facet: [
    {
    id: ‘Booking’,
    purpose: #STANDARD,
    type: #IDENTIFICATION_REFERENCE,
    label: ‘Booking’,
    position: 10 }
    ]

    @UI: {
    lineItem: [ { position: 10, label: ‘Booking ID’, importance: #HIGH },
    { type: #FOR_ACTION, dataAction: ‘set_status’, label: ‘Set Status’} ],
    identification:[ { position: 10, label: ‘Booking ID’ } ]
    }

    key booking as Booking,

    @UI: {
    lineItem: [ { position: 20, label: ‘Customer’, importance: #HIGH } ],
    identification:[ { position: 20, label: ‘Customer’ } ]
    }
    @Search.defaultSearchElement: true
    customername as CustomerName,

    @UI: {
    lineItem: [ { position: 30, label: ‘No of Passengers’, importance: #HIGH } ],
    identification:[ { position: 30, label: ‘No of Passengers’ } ]
    }
    numberofpassengers as NumberOfPassengers,

    @UI: {
    lineItem: [ { position: 50, label: ‘Email’, importance: #HIGH } ],
    identification:[ { position: 40, label: ‘Email’ } ]
    }
    emailaddress as EmailAddress,

    @UI: {
    identification:[ { position: 50, label: ‘Country’ } ]
    }
    country,

    @UI: {
    identification:[ { position: 60, label: ‘Booked On’ } ]
    }
    dateofbooking as DateOfBooking,

    @UI: { identification:[ { position: 70, label: ‘Traveling on’ } ] }
    dateoftravel as DateOfTravel,

    @UI: {
    lineItem: [ { position: 40, label: ‘Cost’, importance: #HIGH } ],
    identification:[ { position: 80, label: ‘Price’ } ]
    }
    @Semantics.amount.currencyCode: ‘CurrencyCode’
    cost,

    @UI: { identification:[ { position: 90, label: ‘Currency’ } ] }
    @Semantics.currencyCode: true
    currencycode as CurrencyCode,

    @UI: { identification:[ { position: 100, label: ‘Last Changed At’ } ] }
    lastchangedat as LastChangedAt,

    //publich associations
    _Country,
    _Currency
    }

     

    Handler class code=>

    CLASS lcl_buffer DEFINITION.
    ENDCLASS.

    CLASS lhc_YI_BOOKING_xxx DEFINITION FINAL INHERITING FROM cl_abap_behavior_handler.
    PRIVATE SECTION.

    METHODS modify FOR BEHAVIOR IMPORTING
    lt_data_to_create FOR CREATE YI_BOOKING_xxx
    lt_data_to_update FOR UPDATE YI_BOOKING_xxx
    lt_data_to_delete FOR DELETE YI_BOOKING_xxx
    lt_data_set_status FOR ACTION YI_BOOKING_xxx~set_status RESULT action_results.

    ENDCLASS.

    CLASS lhc_YI_BOOKING_xxx IMPLEMENTATION.

    METHOD modify.
    DATA lt_data TYPE STANDARD TABLE OF ypsb_booking_xxx.

    ” To create a new entry in the business object +++
    IF lt_data_to_create IS NOT INITIAL.
    lt_data = CORRESPONDING #( lt_data_to_create ).
    MODIFY ypsb_booking_xxx FROM TABLE @lt_data.
    ENDIF.

    ” To update an existing entry in the business object +++
    IF lt_data_to_update IS NOT INITIAL.
    lt_data = CORRESPONDING #( lt_data_to_create ).
    UPDATE ypsb_booking_xxx FROM TABLE @lt_data.
    ENDIF.

    ” To delete an existing entry in the business object +++
    IF lt_data_to_delete IS NOT INITIAL.
    lt_data = CORRESPONDING #( lt_data_to_create ).
    DELETE ypsb_booking_xxx FROM TABLE @lt_data.
    ENDIF.

    ” To handle an action on the business object +++
    IF lt_data_set_status IS NOT INITIAL.
    DATA(ls_data) = CORRESPONDING ypsb_booking_xxx( lt_data_to_create[ 1 ] ).
    ENDIF.
    ENDMETHOD.

    ENDCLASS.

    CLASS lsc_YI_BOOKING_xxx DEFINITION INHERITING FROM cl_abap_behavior_saver.
    PROTECTED SECTION.

    METHODS check_before_save REDEFINITION.

    METHODS finalize REDEFINITION.

    METHODS save REDEFINITION.

    ENDCLASS.

    CLASS lsc_YI_BOOKING_xxx IMPLEMENTATION.

    METHOD check_before_save.
    ENDMETHOD.

    METHOD finalize.
    ENDMETHOD.

    METHOD save.

    ENDMETHOD.

    ENDCLASS.

     

     

     

  • Nice Way of Explaining the Concept in Detail. Its really helpful blog for the Developers to Understand the RAP Concept and your Example for this blog is much helpful as well. Thanks a lot.

    Regards

    Ram

  • Hi Sony,

    Great Blog and good introduction to RAP.

    Sony Sukumar Kattoor – Couple of questions on this model and strategy that SAP is moving towards:

    1. Is this applicable to only SCP – ABAP Runtime Instance where you can locally query the tables in SCP and provide them as a service for consumption?
    2. How does this Programming model impact the S4 on-prem systems? In What scenarios we would use this on-prem?
    3. In On-Prem / Could we can define CDS View and then expose them as oData through annotations and this can be consumed in WebIDE for Fiori apps? I do not fully understand the difference between these 2 approaches. Can you shed some light?
    • Hi Raj,

       

      1) RAP was released for cloud now it is available on Prem from 1909.

      2 and 3) Normally for CDS based BOPF, we will first create BO using CDS and then it will be exposed to SAP GW, but here in RAP, in Behavior implementation, we can use existing BAPI’s and API and this model is Protocolagnostic.Hope this helps you.

  • Hi¬† Sony,

    Really useful explanation and demo for RAP.

    The ABAP Programming model for SAP Fiori (Current best practice) is already powerful to deliver Fiori app/OData Service/API for both cloud and OP, CDS view integrated well with BOPF, ¬†it is efficient and easy for draft handling, lock handling, validation, determination within BOPF object generated by CDS View Annotation.¬† What’s the limitation of current best practice? Why need RAP? What‚Äôs the current best practice cannot do but RAP support for SAP Cloud strategy?

    Thank you for your reply in advance.

     

    • Hi Tikeer,

      Normally for CDS based BOPF, we will first create BO using CDS and then it will be exposed to SAP GW, but here in RAP, in Behavior implementation, we can use existing BAPI’s and API. RAP is investing in Draft and it will be more powerful with future releases.

      • Sony Sukumar Kattoor

        My next questions to you would be, if a customer is running onprem-1909, then what is advised for the developers to chose? Will it be be CDS based BOPF or RAP ? Or that depends on the use case and requirements and if so could you please explain them at high level.

        On an additional note, my understanding is, use CDS based BOPF for Greenfield implementation  involving transactional requirements and plain CDS for read only use cases.

        Secondly use RAP for brownfield requirements which involves using BAPI’S, RFC & Functional modules.

        Please correct me if my understanding is wrong. Thank you for your inputs and appreciate your help.

        Regards

        Praba

        • We cannot use BAPI which include ‘commit’ statement. When BAPI is called, we get error BEHAVIOR_ILLEGAL_STATEMENT. I tried to use BAPI_SALESORDER_CHANGE and got this error message.

          Header Information

          Short Text¬† Statement “CALL FUNCTION .. IN UPDATE TASK” is not allowed with this status.
          Runtime Error  BEHAVIOR_ILLEGAL_STATEMENT
          Program  SAPMV45A
          Date/Time  06.07.2020 14:38:15 (System)
          User 
          Client 
          Host 

          What happened?

          Error in the ABAP application program.

          The current ABAP program “SAPMV45A” had to be terminated because it found a
          statement that could not be executed.

          Error analysis

          There is probably an error in the program
          “SAPMV45A”.
          A BEHAVIOR implementation is active for XYZ While this is the case,
          the following ABAP statements are illegal:

          – COMMIT
          – ROLLBACK
          – SUBMIT
          – CALL TRANSACTION
          – LEAVE
          all DYNPRO-related statements, such as MESSAGE, CALL DIALOG, and CALL
          SCREEN

          The following statement is only allowed in the “Save‚ÄĚ phase: – CALL
          FUNCTION IN UPDATE TASK

           

  • Not sure if relevant, but when I try to create a Behavior definition via ADT – I get the following error message:

    Behavior Definition Validation Service not available

     

    I have checked S4CORE version and it is 103, SP 2.

    What else I might be missing?

    Thank you in advance.

  • Hi Sony,

     

    Thanks for your detail sharing. I met one issue during Unit Test. There is no EML for GET_FEATURES request, and this method can’t be accessed directly as they are private sections.

    How can we write UT for the GET_FEATURES method?

     

    Regards

    Gavin

  • Thanks Sony for sharing, very nice!

    I wonder how would you make it to enable an action for all instances of an entity? In the sample of this blog, to make visible the button to set as favourite but all instances at once, not having to select any of them to be triggered?

    Thanks.

    Regards,

    Daniel

    • Do you mean instead of the radio button, you need a checkbox and then enable action for those items selected in UI?

      In this case, you have to do 2 changes:-

      1. In UI you have to make changes to enable the checkbox instead of a radio button.
      2. In Behavior definition action

        change result[1] $self to result[0..*] $self; and change behavior implementation accordingly , this might work.

  • Hi Sony,

    i have scenario like some fields need to restriction while create option like create date,last changed date etc.i have tried with @UI.hidden: #(CreateAction) but not working.

    any idea to achieve this.