Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
anmolamb
Participant

RestFul ABAP programming model for S4HANA


Since 1909 release SAP came up with new innovation in the programming model of SAP for Services.

That is RESTFul programming Model ( RAP),  this is huge improvement over current BOPF framework and has lots of advantages. There is some blogs explaining more about RAP some of them are listed below.

https://developers.sap.com/tutorials/abap-environment-persistence.html

https://help.sap.com/doc/59d5e6b765eb49c5884a94de512e8259/LATEST/en-US/ABAP_RESTful_Programming_Mode...

In above link the concept is very well explained. Please go through these blogs to get deeper knowledge about the this exciting concept

The purpose of this document is to show the capabilities of RAP with on Premise setup and see how exactly this is different than BOPF.

Basically there are 3 implementation scenarios possible for RAP

  • Managed ( Green field development )

    1. Managed Scenarios are more like BOPF where you define what tables will be updated at end of the process.

    2. We have options for implementing actions, determination and validations

    3. Only available on S4HANA cloud



  • Managed with save ( Self implemented )

    1. These are more sophisticated implementation types where data is not directly updated into tables

    2. BAPIs, update function modules can be called in the implementation to save the data

    3. As of now it is for SAP internal purpose and not delivered to Customers



  • Unmanaged

    1. In this scenario the implementation decides business logic

    2. In the implementation developer can process the input data and update the respective tables or also call BAPIs, functions etc.

    3. Available for S4HANA 1909 OnPremise customers as well

    4. We cannot use validation and determination on field levels.




As you can see that RAP is still in its evaluation state but its worth already start working with it and exploring it.

The major benefit of RAP is first it now follows global development paradigm for Web development i.e. REST services.  This makes it uniform with all other programming languages and also makes integration with system much easy.

Another benefit is, it does not create bunch of objects like BOPF. The implantation is very LEAN.

It does not create new classes with every implementation, does not create lots of structures etc. also SEWG project is not created for RAP.

It also cuts the annotation assignments to CDS views (Hence we have to remember less annotation keywords).

As we proceed with the example I will try to highlight the difference between current (BOPF) and RAP

In this document we will consider Unmanaged Scenario as this is also available for OnPrem (S4HANA1909) customers.

Our example scenario is as follows

We would like to create, update, delete, display the Service entry for the Auto Service industry (Please note this is taken only for example)

P.S Since covering all these actions in this single blog will be to much information, I will only cover Create and Display actions in this blog and publish another one with other actions and options.

Basic setup

 

We would need 2 tables (header and item) to store the Service order and also a basic CDS view.

Header Table
@EndUserText.label : 'Service order header table'
@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #LIMITED
define table zserv_ordhd {
key client : abap.clnt not null;
key sord : char10 not null;
partner : bu_partner;
status : char1;
priority : char1;
@Semantics.amount.currencyCode : 'zserv_ordhd.currkey'
estcost : abap.curr(5,2);
currkey : abap.cuky;
include /bobf/s_lib_admin_data;
}

Item Table



@EndUserText.label : 'Service Order item table'
@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #LIMITED
define table zserv_orditm {
key client : abap.clnt not null;
key sord : char10 not null;
key sitm : numc3 not null;
servcode : char10;
servdescr : char50;
itemstatus : char1;
@Semantics.amount.currencyCode : 'zserv_ordhd.currkey'
partcost : abap.curr(5,2);
labourcode : char10;
labourcat : char1;
labstarttime : timestampl;
labendtime : timestampl;
}

CDS view for Header table
@AbapCatalog.sqlViewName: 'ZISERVORDHDR'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Service order header interface view'
@VDM.viewType: #BASIC
define view ZI_SERV_ORDHRD as select from zserv_ordhd
association [0..*] to ZI_SERV_ORDITM as _Item on $projection.ServiceOrd = _Item.ServiceOrd{
key sord as ServiceOrd,
partner as Customer,
status as Status,
priority as Priority,
//zserv_ordhd
@Semantics.amount.currencyCode: 'Currency'
estcost as EstimatedCost,
currkey as Currency,
/*--Admin data */
@Semantics.systemDate.createdAt: true
crea_date_time as CreatedOn,
@Semantics.user.createdBy: true
crea_uname as CreatedBy,
@Semantics.systemDate.lastChangedAt: true
lchg_date_time as ChangedOn,
@Semantics.user.lastChangedBy: true
lchg_uname as ChangedBy,
//Associations
_Item
}

CDS view for Item table
@AbapCatalog.sqlViewName: 'ZISERVORDITEM'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Service order item interface view'
@VDM.viewType: #BASIC
define view ZI_SERV_ORDITM
as select from zserv_orditm
association [1..1] to ZI_SERV_ORDHRD as _Header on $projection.ServiceOrd = _Header.ServiceOrd
{
//zserv_orditm
//zserv_orditm
key sord as ServiceOrd,
key sitm as ServiceItem,
servcode as ServiceCode,
servdescr as ServiceDescription,
itemstatus as ItemStatus,
@Semantics.amount.currencyCode: '_Header.Currency'
partcost as PartCost,
labourcode as LabourCode,
labourcat as LabourCategory,
labstarttime as LabourStartTime,
labendtime as LabourEndTime,
//Associations
_Header
}

 

Until this step there is no difference with our usual procedure and RAP.

Next step for us is to create the Consumption views.

 

Consumption Views

While doing this we should define which View is Parent View ( Root View ) and connect all Children to this view.

Let’s create the Root Consumption view for our Header table
@AbapCatalog.sqlViewName: 'ZCSERVORDHDRR'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Service Order Cons View with RAP'
@VDM.viewType: #CONSUMPTION
@Search.searchable: true
@UI.headerInfo: { typeName: 'Service Order', typeNamePlural: 'Service Orders', title: { type: #STANDARD, value: 'ServiceOrd' } }
define root view ZC_SERV_ORDHDR_REST
as select from ZI_SERV_ORDHRD
composition [0..*] of ZC_SERV_ORDITEM_REST as _Item
{
//ZI_SERV_ORDHRD
@UI.facet: [
{
id: 'ServiceHeader',
type: #COLLECTION,
position: 10,
label: 'Service Orders'
},
{
type: #FIELDGROUP_REFERENCE,
position: 10,
targetQualifier: 'GeneralData1',
parentId: 'ServiceHeader',
isSummary: true,
isPartOfPreview: true
},
{
type: #FIELDGROUP_REFERENCE,
position: 20,
targetQualifier: 'GeneralData2',
parentId: 'ServiceHeader',
isSummary: true,
isPartOfPreview: true
},
{
id: '_Item',
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
label: 'Item details',
position: 10,
targetElement: '_Item'
}
]

@UI.lineItem: [{position: 10, importance: #HIGH, label: 'Service Order' }]
@UI.fieldGroup: [{qualifier: 'GeneralData1',position: 10,importance: #HIGH, label: 'Service Order' }]
@UI.selectionField: [{position: 10 }]
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.9
@UI.hidden: #(CreateAction)
key ServiceOrd,
case when ServiceOrd is initial then cast ( 'X' as bool )
else cast( ' ' as bool ) end as CreateAction,
@UI.lineItem: [{position: 20, importance: #HIGH, label: 'Customer' }]
@UI.fieldGroup: [{qualifier: 'GeneralData1',position: 20,importance: #HIGH, label: 'Customer' }]
@UI.selectionField: [{position: 20 }]
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.9
Customer,
@ObjectModel.text.element: ['StatusTxt']
@UI.lineItem: [{position: 30, importance: #HIGH, label: 'Status', criticality: 'StatusCriticality' }]
@UI.fieldGroup: [{qualifier: 'GeneralData2',position: 10,importance: #HIGH, criticality: 'StatusCriticality', label: 'Status' }]
@UI.selectionField: [{position: 30 }]
@UI.hidden: #(CreateAction)
Status,
@Semantics.text: true
case when Status = '1' then 'Open'
when Status = '2' then 'Approval'
when Status = '3' then 'In Progress'
when Status = '4' then 'Completed' else '' end as StatusTxt,
case when Status = '1' then 1
when Status = '2' then 2
when Status = '3' then 2
when Status = '4' then 3 else 1 end as StatusCriticality,
@ObjectModel.text.element: ['PriorityTxt']
@UI.lineItem: [{position: 40, importance: #HIGH, label: 'Priority' }]
@UI.fieldGroup: [{qualifier: 'GeneralData2',position: 20,importance: #HIGH, label: 'Priority' }]
@UI.selectionField: [{position: 40 }]
Priority,
@Semantics.text: true
case when Priority = '1' then 'Urgent'
when Priority = '2' then 'Major'
when Priority = '3' then 'Medium'
when Priority = '4' then 'Minor' else 'Minor' end as PriorityTxt,
@UI.lineItem: [{position: 50, importance: #HIGH, label: 'Estimated Cost', criticality: 'StatusCriticality' }]
@UI.fieldGroup: [{qualifier: 'GeneralData1',position: 30,importance: #HIGH, label: 'Estimated Cost', criticality: 'StatusCriticality' }]
EstimatedCost,
case when EstimatedCost > 500 then 'X'
else '' end as approvalNeeded,

@UI.lineItem: [{position: 60, importance: #HIGH, label: 'Actual Cost' }]
@UI.fieldGroup: [{qualifier: 'GeneralData1',position: 40,importance: #HIGH, label: 'Actual Cost' }]
@Semantics.amount.currencyCode: 'Currency'
@UI.hidden: #(CreateAction)
cast(0 as abap.curr(5,2) ) as ActualCost,
@UI.lineItem: [{position: 70, importance: #MEDIUM, label: 'Currency' }]
@UI.fieldGroup: [{qualifier: 'GeneralData1',position: 50,importance: #MEDIUM, label: 'Currency' }]
Currency,
@UI.lineItem: [{position: 80, importance: #MEDIUM, label: 'Created On' }]
@UI.fieldGroup: [{qualifier: 'GeneralData2',position: 30,importance: #MEDIUM,label: 'Created On' }]
@UI.selectionField: [{position: 50 }]
@UI.hidden: #(CreateAction)
CreatedOn,
@UI.lineItem: [{position: 90, importance: #MEDIUM, label: 'Created By' }]
@UI.fieldGroup: [{qualifier: 'GeneralData2',position: 40,importance: #MEDIUM,label: 'Created By'}]
@UI.selectionField: [{position: 60 }]
@UI.hidden: #(CreateAction)
CreatedBy,
@UI.lineItem: [{position: 100, importance: #LOW, label: 'Changed On' }]
@UI.fieldGroup: [{qualifier: 'GeneralData2',position: 50,importance: #LOW,label: 'Changed On' }]
@UI.hidden: #(CreateAction)
ChangedOn,
@UI.lineItem: [{position: 110, importance: #LOW, label: 'Changed By' }]
@UI.fieldGroup: [{qualifier: 'GeneralData2',position: 60,importance: #LOW,label: 'Changed By' }]
@UI.hidden: #(CreateAction)
ChangedBy,
/* Associations */
//ZI_SERV_ORDHDR_TP
_Item
}

Now same way create Item consumption view
@AbapCatalog.sqlViewName: 'ZCSERORDITR'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Service order Item cons view RAP'
@UI.headerInfo: { typeName: 'Service Order Item', typeNamePlural: 'Service Order Items', title: { type: #STANDARD, value: 'ServiceOrd' } }

define view ZC_SERV_ORDITEM_REST
as select from ZI_SERV_ORDITM
association to parent ZC_SERV_ORDHDR_REST as _Header on $projection.ServiceOrd = _Header.ServiceOrd
{
//ZI_SERV_ORDITM
@UI.facet: [
{type: #COLLECTION, position: 10, id: '_Item', label: 'Idoc details'},
{type: #FIELDGROUP_REFERENCE, position: 10, targetQualifier: 'Item1',parentId: '_Item', isSummary: true, isPartOfPreview: true},
{type: #FIELDGROUP_REFERENCE, position: 20, targetQualifier: 'Item2',parentId: '_Item', isSummary: true, isPartOfPreview: true}
]
@UI.lineItem: [{position:10,importance: #HIGH, label:'Service Order' }]
@UI.fieldGroup: [{qualifier: 'Item1', label:'Service Order', position:10,importance: #HIGH}]
key ServiceOrd,
@UI.lineItem: [{position:20,importance: #HIGH, label: 'Order Item' }]
@UI.fieldGroup: [{qualifier: 'Item1', position:20, label: 'Order Item',importance: #HIGH}]
key ServiceItem,
@UI.lineItem: [{position:30,importance: #MEDIUM , label: 'Service code'}]
@UI.fieldGroup: [{qualifier: 'Item1', position:30, label: 'Service code',importance: #HIGH}]
ServiceCode,
@UI.lineItem: [{position:40,importance: #MEDIUM , label:'Service description'}]
@UI.fieldGroup: [{qualifier: 'Item1', position:40, label:'Service description',importance: #HIGH}]
ServiceDescription,
@UI.lineItem: [{position:50,importance: #HIGH, label: 'Item status', criticality: 'ItemCriticality' }]
@UI.fieldGroup: [{qualifier: 'Item2', position:10,importance: #HIGH, label: 'Item status', criticality: 'ItemCriticality'}]
@ObjectModel.text.element: ['ItemStatusTxt']
ItemStatus,
@Semantics.text: true
case when ItemStatus = '1' then 'Open'
when ItemStatus = '2' then 'In Progress'
when ItemStatus = '3' then 'Complete'
else '' end as ItemStatusTxt,
case when ItemStatus = '1' then 1
when ItemStatus = '2' then 2
when ItemStatus = '3' then 3
else 1 end as ItemCriticality,
@UI.lineItem: [{position:60,importance: #MEDIUM, label:'Labour code' }]
@UI.fieldGroup: [{qualifier: 'Item1', position:50, label:'Labour code',importance: #HIGH}]
LabourCode,
@UI.lineItem: [{position:70,importance: #MEDIUM, label:'Labour Category' }]
@UI.fieldGroup: [{qualifier: 'Item1', position:60, label:'Labour Category',importance: #HIGH}]
LabourCategory,
@UI.fieldGroup: [{qualifier: 'Item1', position:70, label:'Part cost',importance: #MEDIUM}]
@Semantics.amount.currencyCode: '_Header.Currency'
PartCost,
//_Header.Currency as Currency,
@UI.fieldGroup: [{qualifier: 'Item1', position:80, label:'Labour starttime',importance: #MEDIUM}]
LabourStartTime,
@UI.fieldGroup: [{qualifier: 'Item1', position:90, label:'Labour Endtime',importance: #MEDIUM}]
LabourEndTime,
/* Associations */
//ZI_SERV_ORDHITEM_TP
_Header
}

The Notable difference with this consumption views are, we cut lots of Annotations.

In older CDS view for BOPF we have to define many ObjectModel Annotations in the Interface and Consumptions Views.



 

The Parent and Child relationship in BOPF was defined at the bottom of the CDS view where we declare the Associations

All of these annotations are not required now as the RAP does not create the BOPF like framework in the background out of these Annotations.

The Difference we see here is how we define the view and how we write the select statement.

To declare the view as Parent we have to use DEFINE ROOT keyword, with this statement the RAP consider this view ad Parent and automatically create the Relationships for all the Views declared with COMPOSITION statement


Other than these 2 differences we don’t need any other special declaration to set up RAP.

While creating Child view we have to use keyword association to parent. This is sufficient for RAP to link these views and create Relationship.


 

That’s it. The basic setup for creating the RAP is completed.

We have usual UI Annotations in these CDS view for UI Representation.

Now let’s go further and create Behavior Definition

 

Behavior Definition

Behavior Definition is used to (name suggest )  define the Behavior of our service. Which means what kind of database activities are allowed, what actions this service should do, Validations etc?

To create the Behavior Definition right click on the Cons View and select “Create Behavior Definition”

Please note: Create Behavior Definition only for the Root View.


In the next screen select the implementation type Unmanaged as this is the only possibility for OnPrem S4HANA1909 to create RAP.



unmanaged implementation in class ZCL_C_I_SERVORD_REST unique;

define behavior for ZC_SERV_ORDHDR_REST alias ServOrd
//late numbering
//lock master
//authorization master
etag ChangedOn
{
field ( read only ) ServiceOrd, ActualCost, Status, CreatedOn, CreatedBy, ChangedOn, ChangedBy;
field ( mandatory ) Customer;
create;
update;
delete;
association _Item { create; }
// action (features : instance) Approved result [1] $self;
}

define behavior for ZC_SERV_ORDITEM_REST alias ServItem
//late numbering
//lock dependent( <local_field_name> = <target_field_name> )
//authorization dependent( <local_field_name> = <target_field_name> )
//etag <field_name>
{
field ( read only ) ServiceOrd, ServiceItem, ItemStatus;
field ( mandatory ) LabourCode, LabourCategory;
create;
update;
delete;
}

In the above code we wrote that some fields are read only, some are mandatory. What database actions can be performed. We can also define custom actions( will be explained in details in next Blog )

We also have to create the Class defined in the Behavior with following Signature
class ZCL_C_I_SERVORD_REST definition
public abstract final for behavior of ZC_SERV_ORDHDR_REST.
endclass.

class ZCL_C_I_SERVORD_REST implementation.
endclass.

 

Don’t worry for the implementation of the class methods for now.  We will look at this later.

Now lets create Service Definition.

Service Definition

In Service Definition, we define what View are exposed in this service.



@EndUserText.label: 'Service Definition for Service Order'
define service ZUI_ZC_SERV_ORDHDR_REST {
expose ZC_SERV_ORDHDR_REST as ServHeader;
expose ZC_SERV_ORDITEM_REST as ServItem;
}

Next step is to create the Service Binding

 

Service Binding

In Service Binding we define what kind of service we want to create. The service can be simple Odata Service which can be consumed by other services or external systems using REST calls or it could be UI service which then creates FIORI element UI5 service.

Let’s create UI service as this is more fun.



Now let’s click on the Activate Service.


And after this the magic begins.

Our service is activated with automatically create Associations Navigation for the Views exposed in the previous step.

Also we can now already see how our UI Service will look like when implemented in WebIDE.


Click on the Preview button and we can see the preview of our FIORI UI5 application already.

In older frameworks, this was not possible we first have to create UI5 application, consume this service and then check the output but here we can Preview it much earlier and make adjustments if needed.


Not only this, you can navigate to next page to check the Item Association.


 

By this point our service with FIORI element is ready, now we have to implement the logic for database activities and any external actions which we defined in Behavior Definition.

So let’s go back to our class ZCL_C_I_SERVORD_REST and add the necessary methods.

We declare and implement these methods in Local Types (don’t ask me exactly why, probably as we have to inherit from 2 classes and ABAP do not support this )

In this class we have to declare local class inheriting from CL_ABAP_BEHAVIOR_HANDLER and declare and implement all the database activity methods as below
*"* use this source file for the definition and implementation of
*"* local helper classes, interface definitions and type
*"* declarations
class LCL_BUFFER definition.

public section.

types: begin of TY_BUFFER_HDR.
include type ZSERV_ORDHD as DATA.
types: FLAG type C length 1,
end of TY_BUFFER_HDR.

types: begin of TY_BUFFER_ITM.
include type ZSERV_ORDITM as DATA.
types: FLAG type C length 1,
end of TY_BUFFER_ITM.
types: tt_SERVORD type sorted table of TY_BUFFER_HDR with unique key SORD.
types: tt_SERVORD_ITM type sorted table of TY_BUFFER_ITM with unique key SORD SITM.

class-data MT_BUFFER_HDR type tt_SERVORD.
class-data MT_BUFFER_ITM type tt_SERVORD_ITM.
endclass.

class LHC_SERVORD definition inheriting from CL_ABAP_BEHAVIOR_HANDLER.
private section.
methods CREATE_HEADER for modify importing ENTITIES for create ServOrd.
methods UPDATE_HEADER for modify importing ENTITIES for update ServOrd.
methods DELETE_HEADER for modify importing ENTITIES for delete ServOrd.
* methods LOCK_HEADER for lock importing KEYS for lock ServOrd.
methods READ_HEADER for read importing KEYS for read ServOrd result RESULT.
methods CREATE_ITEM for modify importing ENTITIES for create ServItem.
methods UPDATE_ITEM for modify importing ENTITIES for update ServItem.
methods DELETE_ITEM for modify importing ENTITIES for delete ServItem.
* methods LOCK_ITEM for lock importing KEYS for lock ServItem.
methods READ_ITEM for read importing KEYS for read ServItem result RESULT.

endclass.

class LHC_SERVORD implementation.

method CREATE_HEADER.
get time stamp field data(LV_TSL).
loop at ENTITIES into data(LS_CREATE).
select max( SORD ) from ZSERV_ORDHD into @data(LV_MAX_SORD). "get last servord num
LV_MAX_SORD = LV_MAX_SORD + 1.
LS_CREATE-%DATA-ServiceOrd = LV_MAX_SORD. "calculate field

LS_CREATE-%DATA-Status = 1. "set default values
LS_CREATE-%DATA-CreatedOn = LV_TSL.
LS_CREATE-%DATA-CreatedBy = SY-UNAME.
append initial line to lcl_buffer=>mt_buffer_hdr assigning field-symbol(<buffer>).
<buffer>-data = corresponding #( ls_create-%DATA ).
<buffer>-data-sord = ls_create-%DATA-ServiceOrd.
<buffer>-data-Partner = ls_create-%DATA-Customer.
if LS_CREATE-%CID is not initial.
insert value #( %CID = LS_CREATE-%CID ServiceOrd = LS_CREATE-ServiceOrd ) into table MAPPED-SERVORD.
endif.
endloop.
endmethod.


method READ_HEADER.

endmethod.

method UPDATE_HEADER.
"nothing to do here

endmethod.

method DELETE_HEADER.
"nothing to do in this method
endmethod.

method CREATE_ITEM.
get time stamp field data(LV_TSL).
loop at ENTITIES into data(ls_itemCreate).
ls_itemCreate-%DATA-ItemStatus = 1.
ls_itemCreate-%DATA-LabourStartTime = LV_TSL.
insert value #( FLAG = 'C' DATA = corresponding #( ls_itemCreate-%DATA ) ) into table LCL_BUFFER=>MT_BUFFER_ITM.
if ls_itemCreate-%CID is not initial.
insert value #( %CID = ls_itemCreate-%CID ServiceOrd = ls_itemCreate-ServiceOrd ServiceItem = ls_itemCreate-ServiceItem ) into table MAPPED-SERVITEM.
endif.
endloop.
endmethod.

method DELETE_ITEM.

endmethod.

method READ_ITEM.

endmethod.

method UPDATE_ITEM.

endmethod.

endclass.

( In this blog only Create methods are implemented, others will follow in next Blog )

In the method implementation, you can add normal ABAP code to perform actions (isn’t this cool).

You can calculate and populate certain fields, add default values etc..

After this we have to declare and implement another local class inheriting from CL_ABAP_BEHAVIOR_SAVER.

This class has methods

CHECK_BEFORE_SAVE – For before save validations

FINALIZE – Final adjustments

SAVE – Actual commit.

In this class we actual write ABAP code to perform the database action.

You can call standard BAPIs or function modules to commit the transactions or also direct update to your custom tables or any other action like creating file on application server etc..
class lsc_ZI_SERV_ORDHDR_TP definition inheriting from CL_ABAP_BEHAVIOR_SAVER.
protected section.
methods CHECK_BEFORE_SAVE redefinition.
methods FINALIZE redefinition.
methods SAVE redefinition.
endclass.

class LSC_ZI_SERV_ORDHDR_TP implementation.

method CHECK_BEFORE_SAVE.

endmethod.

method FINALIZE.

endmethod.

method SAVE.
data: LT_DATA_HDR type standard table of ZSERV_ORDHD.
data: LT_DATA_ITM type standard table of ZSERV_ORDITM.

LT_DATA_HDR = value #( for ROW in LCL_BUFFER=>MT_BUFFER_HDR where ( FLAG = 'C' ) ( ROW-DATA ) ).
if LT_DATA_HDR is not initial.
insert ZSERV_ORDHD from table @LT_DATA_HDR.
endif.
LT_DATA_ITM = value #( for ROW_ITM in LCL_BUFFER=>MT_BUFFER_ITM where ( FLAG = 'C' ) ( ROW_ITM-DATA ) ).
if LT_DATA_ITM is not initial.
insert ZSERV_ORDITM from table @LT_DATA_ITM.
endif.

endmethod.

endclass.

 

Last step is to consume this newly created service in our SAP WebIDE and created FIORI element application.

Create FIORI Element application

 

Follow same steps like we consume other services


 


 



At the end of this our service is ready with read and write action along with custom logic for writing the data back to database. You can now enhance the class implementation of the Behavior definition and add further logic. Also we have all the possibilities to enhance the FIORI element app like any other FIORI element development.

 

Summery

RAP ( RestFul ABAP Programming ) Model is very promising, it is very flexible but at the same time reliable. There will be more development and changes coming in this direction in future releases. It leaves less database footprint as it does not create lots of artifacts for every application. We will keep looking for the updates on this topic.
19 Comments
joachimrees1
Active Contributor
Thanks for the detailed example!
former_member16553
Active Participant
Nice blog ! Thanks!
AndyS
Explorer
Hi Anmol,

Great blog post about RAP!
former_member682010
Discoverer
Very useful blog. Thanks for the blog. Waiting for your next blog. 🙂
md1992india
Explorer
anmolamb : If we are having existing standard BOPF, and we are working on BOPF,CDS, Odata framework and we have to switch to RAP. Then we will have to go for unmanaged BIMP? and how will we be using existing BOPF in this case?
anmolamb
Participant
0 Kudos
Hi md1992india

I think replacement of existing BOPF application for SAP and for customers will a long term exercise.

I hope SAP will keep both solutions working for longer time.

Regarding which Implementation should be followed - It completely dependent on Scenario.

Most BOPF application with less enhancements and code might be going towards Managed Implementation. Managed Implementation also offers validation, user actions etc...

Unmanaged and Managed with Save gives us more options to write plane ABAP code and have custom logic while saving the data in the DB or call standard BAPI etc.

Regarding  Reusing objects from BOPF - I am not sure which components of BOPF can be reuse in RAP. Probably only the Code from our Validations and action only.

I hope you get what you are looking for.

Regards,

Anmol
md1992india
Explorer
0 Kudos
Thanks. Yes it answers my question and any views about draft functionality ? How can we use BOPF draft functionality in RAP?
0 Kudos
Hi Anmol,

 

Very interesting and nice Blog. Also you have explained the steps and their purpose very clearly. Thanks for such a good blog.

Any clue on when will you be publishing the next blog in the series.

 

Neelesh
alvin_fan
Advisor
Advisor
0 Kudos
Hi Anmol,

You have explained the steps and their purpose very clearly.Thanks for sharing.

Looking forward to the next blog in this series.
0 Kudos
Hi Anmol,

Even though I had defined behaviour definition 'CREATE' for items section, am not able to see any item fields in CREATE screen. Only I can able to see the HEADER fields?

Is there any thing, am I missing?
0 Kudos
Hi,

 

I try to reproduce the case. But I couldn't make. I have issue with line item to be displayed on detail page.

I done all the steps explained above. In details page, I can able to se the Service Order table, But there is no Item table . My item information is not shown.

Can you please help to solve the issue. is there any special parameter or UI annotation do I have to make in CDS view display the Item details..
pramodu
Active Participant
0 Kudos
Thanks Anmol !!   Good stuff to know .
Hello All,

I am trying to create an entry in the header table using the Create Header Method.

I am getting the error











Short Text  Assignment error: Overwriting of a protected field.
Runtime Error  MOVE_TO_LIT_NOTALLOWED_NODATA

Field "<BUFFER>-CLIENT" was to assigned a new value but this field is at least partly
protected against changes.

Did anyone faced this issue when posting the data to the DB table
0 Kudos
Hi anmolamb ,

I am trying to use standard BAPI which does an internal commit and updates a Revision.
when I am using this in SAVE method, the RAP framework gives me a dump.

Can you please help?
Regards,

Udita
DineshK
Active Participant
0 Kudos
Hi, Can you let us know if you have found out any workaround to this issue ...
martin1903
Explorer
0 Kudos
I  tried out the example. After fixing some bugs i finally can create a header-entry. Then i can go to the detail page. When i try to create a detail-entry there are two errors i get:

  1. The partCost fileld will not convert and has always three number after decimal also by the currency EUR (will the semantic-key ignored?)

  2. When i leave the field for partCost empty and click on save then i get a sadl-short-dump What's wrong? There is no hint which makes sense.


Can anyone help please?

Regards,

Martin
anmolamb
Participant
Hi Udita,

I dont know if you still have the problem. If yes I think the problem could be that there is a commit work. RAP does not expect to have exclusive commit work.

 
kawatra02
Explorer
0 Kudos
Hi anmolamb,

 

Can you please tell me, How to handle Warning or Error messages in an Unmanaged Scenario?

 

 

Regards,

Himanshu Kawatra
VinothT
Explorer
0 Kudos
Hi Himanshu,

Were you able to implement error handling in unmanaged scenario?
Labels in this area