Skip to Content
Technical Articles
Author's profile photo Sony Sukumar Kattoor

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.

 

Assigned tags

      47 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Yugandhar V
      Yugandhar V

      Nice Blog.. sony

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      Thanks Yugandhar

      Author's profile photo abhijeet kankani
      abhijeet kankani

      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

      Author's profile photo Mahesh Kumar Palavalli
      Mahesh Kumar Palavalli

      Yeah, It is currently released in cloud and in 1909 release, it will come to on premise.

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      Thanks Mahesh for the quick response:)

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      Thanks Abhijeet:) as Mahesh mentioned it is currently part of cloud release .

      Author's profile photo Nabheet Madan
      Nabheet Madan

      Great stuff and recap!

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      Thanks Nabheet:)

      Author's profile photo Prasenjit Singh Bist
      Prasenjit Singh Bist

      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.

       

       

       

      Author's profile photo Uttam Kumar
      Uttam Kumar

      Is it right that we cannot develop a service of its own and develop a Fiori Like application using RAP until we move to cloud?

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      Hi Uttam

      RAP on prem is released as part of 1909 

      Author's profile photo Sriram Kompell
      Sriram Kompell

      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

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      Thanks Sriram ūüôā

      Author's profile photo kumar manish
      kumar manish

      Hi Sony,

      Great blog to understand the RAP model with example.Thanks.

      Regards,

      Manish Kumar

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      Thanks Manish ūüôā

      Author's profile photo Syambabu Allu
      Syambabu Allu

      Hi Sony,

      I have tried this and working as expected ūüôā

      thanks for sharing this blog in detail!

      Thanks,

      Syam

       

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      Thanks Syam

      Author's profile photo Marcella Penha
      Marcella Penha

      Hi Sony! How did you configure the destination on SAP Cloud Platform cockpit? I'm stuck in this part.. Thanks in advance.

      Author's profile photo Alessandra Souza
      Alessandra Souza

      Hi Marcella Penha, you can create a project from template based on the Multi-Target Application on WebIDE. Then you right-click the name of your project > New > SAP Cloud Platform, and it will open a pop-up where you can search for ABAP and add the service from your Dev Space. You can follow the steps in this tutorial: https://developers.sap.com/tutorials/abap-environment-deploy-cf-production.html

      Author's profile photo Marcella Penha
      Marcella Penha

      Thanks a lot, Alessandra!

      Author's profile photo Raj K
      Raj K

      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?
      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      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 Protocol-agnostic.Hope this helps you.

      Author's profile photo Tikeer Guo
      Tikeer Guo

      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.

       

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      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.

      Author's profile photo Prabaharan Asokan
      Prabaharan Asokan

      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

      Author's profile photo Sunil H
      Sunil H

      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

       

      Author's profile photo kyo choi
      kyo choi

      Can you provide the code and system version?  Are you on Cloud version or on-prem 1909?

      Author's profile photo Germ√°n Laso
      Germ√°n Laso

      I have the same issue trying to create an invoice. Did you solve this issue?

      Thank you in advance.

      Author's profile photo Raju Venkata
      Raju Venkata

      Have u find any solution for this ?

      Author's profile photo Pradeep Pandey
      Pradeep Pandey

      Hi Sony Sukumar Kattoor

      It is really a very helpful blog.

      we are also facing the same situation with BAPI_EQUI_CREATE which calls an FM in update task which was causing the issue in create method. To solve that I moved the Bapi call in Save method of behaviour implementation call and now we are able to create equipment, but we are unable to send back any success/error response as the SAVE method doesn't have any parameter.

      Is there any way by which we can pass the response back from the SAVE method?

       

      Thanks

      Pradeep

      Author's profile photo iMRO DEV TEAM
      iMRO DEV TEAM

      Hi PRadeep,

      How did you pass the entity values to the SAVE method.

      I am unable to carry values from my behaviour implementation method to the standard SAVE method.

       

      Author's profile photo Umut Yazici
      Umut Yazici

      I think you should use create, update or read method to carry values.

      Look at this example: https://github.com/SAP-samples/abap-platform-rap-opensap/blob/main/week4/unit3.md

      METHOD create.
        
       DATA legacy_entity_in  TYPE test.
      
            legacy_entity_in = CORRESPONDING #( <entity> MAPPING FROM ENTITY USING CONTROL ).
      
      
      CALL FUNCTION 'ABC'
              EXPORTING
                is_input   = legacy_entity_in 
              IMPORTING
                es_output   = legacy_entity_out
      
      
      ENDMETHOD.
      
      
      METHOD save.
      CALL FUNCTION 'ABC_SAVE'.
      ENDMETHOD.
      Author's profile photo Bruno Desmedt
      Bruno Desmedt

      Same issue here... did you create a ticket for this?

      Author's profile photo Ilja Mihailovs
      Ilja Mihailovs

      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.

      Author's profile photo Ravi Singh
      Ravi Singh

      Nice blog. Do you have any idea how do we implement Etags and locks in the unmanaged scenario ?

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      We have options for Etag and lock  in behavior definition

      Author's profile photo Gavin Wang
      Gavin Wang

      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

      Author's profile photo Daniel Ojados Conesa
      Daniel Ojados Conesa

      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

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      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.

      Author's profile photo Manjeet Dang
      Manjeet Dang

      HI Sony,

      Can you please tell how to handle draft feature in managed?

      Author's profile photo Arnold Mirashi
      Arnold Mirashi

      Hi Sony ,

       

      When I use VKORG as data element it says that it is not permitted !

      Author's profile photo karimulla mahammad
      karimulla mahammad

      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.

       

       

      Author's profile photo Sony Sukumar Kattoor
      Sony Sukumar Kattoor
      Blog Post Author

      Use field (read only ) field1; at behavior definition level then it will be reflected as read-only for that field in UI

      Author's profile photo karimulla mahammad
      karimulla mahammad

      Yes, is there any possibility of in create scenario  hide the fields completely. bcoz those field not required at create action.

      Author's profile photo RAMAKRISHNAN MURUGAN
      RAMAKRISHNAN MURUGAN

      Hi SOny,

      I can see item fields for READ operation. But am not able to see item fields in CREATE scenario. I can see only Header fields. Am I missing any thing?

       

      BR,

      RAM.

      Author's profile photo Om Prakash Jha
      Om Prakash Jha

      Nice Blog!

      Author's profile photo iMRO DEV TEAM
      iMRO DEV TEAM

      Hi Sony,

      We are trying to extend a Root CDS and added a new association to the extended CDS.
      Now we all know that unless the association is not exposed in service definition it cannot be consumed by UX. So the CDS is extended, is there also a framework where service definition can be extended and the new association is exposed there?.

      Thanks & Regards,

      Udita Saklani