Personal Insights
RAP Based Events in SAP S/4HANA Cloud ABAP Environment ( aka Embedded Steampunk )
Event Driven Architecture has gained a lot of popularity in recent times as businesses are looking to leverage it to become flexible , agile and scalable. Events are used more and more for real time integration with 3rd party systems without the need to extend the core. There are great many blogs already written about Event Driven Architecture and Event Mesh and how to configure event mesh to send events from S/4HANA On-Premise or cloud system to BTP Event mesh. This blog is focused more on ABAP RESTful Application Programming Model ( RAP ) based events introduced as part of the recent release.
With the release of BTP ABAP environment 2208 and developer extensibility( Embedded Steampunk) in S/4HANA Cloud , ABAP RESTful Application Programming Model framework now supports event driven architecture natively. Events represent a significant change of state of the RAP business objects or of one of its child entity that is relevant for follow-up processes . RAP BO’s can act as both Event Consumer and Event Producer.
Just like the standard SAP S/4HANA On-Premise or Cloud events RAP based events too work together with event mesh as a message broker to produce or receive events , we will continue the discussion with the assumption that Event mesh is already configured in your system and Channels are already set up for outbound topic binding.
RAP Business Objects as Event Consumers
Events can be consumed from the Event Mesh Queue using the newly introduced event consumption model . Event Consumption Model can be created using the AsyncAPI JSON file for a particular event , the consumption model based on the payload mentioned in the AsyncAPI JSON creates an abstract entity , consumer class and a consumer extension class , the consumer extension class can then be used to plugin our custom logic on how the event should be handled. For Example a sales order can be created using a RAP BO based on the event payload.
Please check the below tutorial which explains in great detail on how to configure Event Mesh in a SAP S/4HANA cloud system and how to Consume Events using the Event Consumption Model.
Event Consumption in ABAP Development Tools using RAP BO
RAP Business Objects as Event Producers
RAP entity events are defined through Behavior Definition on root node level for both managed and unmanaged scenario. Entity events can have a parameter ( Abstract CDS Entity ) which acts as the event payload and is optional. If no parameter is defined the keys for the root BO is used as the event payload. The RAP Event created will be then mapped to a event type using “Event Binding” which will allow the event to be configured as an Outbound Topic in our event mesh Channel. This topic is then subscribed by an event mesh queue for further processing, messages can be consumed by 3rd party systems from the queue directly.
The event can also be triggered from outside the RAP Business object by wrapping the “Raise Event” in a local class in the behavior pool class and calling the same by creating static method in the global class pool of the behavior implementation class. This static method can be then used to raise the events from outside the RAP BO by passing the payload as an importing parameter.
For this use case a simple RAP BO is created which will send an event for every new instance created using the RAP BO , a parameter is defined for the event using an abstract entity that acts as payload structure to send additional Contact Details along with the partner number created. Keyword “RAISE ENTITY EVENT” is then used to raise the event when a new instance is created , this is implemented within its own behavior pool using an additional save.
Interface View
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Interface View for Contact Info'
define root view entity ZI_CONINFO
as select from ztabconinfo
{
key bpno as Bpno,
firstname as Firstname,
lastname as Lastname,
@Semantics.eMail.address: true
email as Email,
@Semantics.user.createdBy: true
local_created_by as LocalCreatedBy,
@Semantics.systemDateTime.createdAt: true
local_created_at as LocalCreatedAt,
@Semantics.user.lastChangedBy: true
local_last_changed_by as LocalLastChangedBy,
//local ETag field --> OData ETag
@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed_at as LocalLastChangedAt,
//total ETag field
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt
}
Consumption View
@EndUserText.label: 'Consumption View for Contact Info'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZC_CONINFO
provider contract transactional_query
as projection on ZI_CONINFO
{
key Bpno,
Firstname,
Lastname,
Email,
LocalLastChangedAt
}
Metadata Extension
@Metadata.layer: #CORE
@UI: { headerInfo: {
typeName: 'User',
typeNamePlural: 'Users',
title: { type: #STANDARD, value: 'Bpno' } },
presentationVariant: [{
sortOrder: [{ by: 'Bpno', direction: #DESC }],
visualizations: [{type: #AS_LINEITEM}] }] }
annotate view ZC_CONINFO with
{
@UI.facet: [ {
label: 'General Information',
id: 'GeneralInfo',
type: #COLLECTION,
position: 10
},
{ id: 'Userdetails',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'User Details',
parentId: 'GeneralInfo',
position: 10 } ]
@UI: { lineItem: [ { position: 10, importance: #HIGH , label: 'User Number'} ] ,
identification: [ { position: 10 , label: 'User Number' } ] }
Bpno;
@UI: { lineItem: [ { position: 20, importance: #HIGH , label: 'First Name'} ] ,
identification: [ { position: 20 , label: 'First Name' } ] }
Firstname;
@UI: { lineItem: [ { position: 30, importance: #HIGH , label: 'Last Name'} ] ,
identification: [ { position: 30 , label: 'Last Name' } ] }
Lastname;
@UI: { lineItem: [ { position: 40, importance: #HIGH , label: 'Email Address'} ] ,
identification: [ { position: 40 , label: 'Email Address' } ] }
Email;
}
Behavior Definition for Interface view
In the below behavior definition the event is defined along with a CDS abstract entity as a parameter. The Keys for the RAP BO along with the parameter makes the payload for the event.
managed implementation in class zbp_i_coninfo unique;
strict ( 2 );
with draft;
define behavior for ZI_CONINFO alias Userdetails
persistent table ztabconinfo
draft table ztabconinfod
lock master
total etag LocalLastChangedAt
authorization master ( instance )
with additional save
{
create;
update;
delete;
field ( readonly ) LastChangedAt, LocalLastChangedBy, LocalLastChangedAt, LocalCreatedBy,
LocalCreatedAt;
event SendContact parameter ZABS_EVENTSTRUC;
draft action Edit;
draft action Activate;
draft action Discard;
draft action Resume;
draft determine action Prepare;
}
CDS Abstract Entity
This will act as the Event Payload along with the RAP BO Key.
@EndUserText.label: 'Event Structure'
define abstract entity ZABS_EVENTSTRUC
{
firstname : abap.char(20);
lastname : abap.char(20);
email : abap.char(20);
created_by : abp_creation_user;
created_at : abp_creation_tstmpl;
}
Raising the event in Save Modified
The event is then raised in Save Modified method of the Implementing class for the behavior definition. For our use case we don’t want to raise an event for update or delete and hence the additional check is performed to ensure that the event is raised only for Create Scenarios.
method save_modified.
if create-userdetails is not initial.
raise entity event zi_coninfo~SendContact
from value #(
for userdet in create-userdetails (
Bpno = userdet-Bpno
firstname = userdet-Firstname
lastname = userdet-Lastname
email = userdet-Email
)
).
endif.
endmethod.
The Behavior definition for the consumption view , the Service definition and the ODataV4 UI Service binding is then created to expose the Business object. Once the Service is published we can then create an event binding to map the RAP Event and RAP BO and create a custom topic which will be the configured in the EM outbound channel for outbound communication.
The Namespace, Business object and Business Object Operation together becomes the topic for this event as can be seen in the field “Type” below.
The Root Entity and the Event defined in the BDEF is then added as shown below to the Event Binding to map it to the name space.
Event Binding
The Event is then available in the dropdown for outbound topics and can be configured in the SAP S/4HANA Cloud Event mesh Channel as an Outbound Topic.
Available under Outbound Topic
RAP Event configured as outbound Topic
This is now ready for consumption and can be subscribed to an event mesh queue as shown below. The message can then be consumed from event mesh queue using the standard consumption model such as AMQP, REST , Webhook or now from another RAP business object.
Topic Subscribed in the EM Queue
To test the application we can then create a new Instance with the corresponding contact details, on saving the contact info an event will be raised which will then send the contact details to the EM queue.
New Instance Created
Message Received in Queue
Event payload
In conclusion, native support of RAP based events dramatically strengthens SAP’s capability to support event driven architecture and gives us as developers the capability make our applications agile and flexible. This will also enable us to extend standard business processes with additional functionality or post processing steps without the need of enhancement keeping the core clean. Using RAP as an event producer we can now have our own custom event which can be used for all the scenarios where Standard events are not available or Simple Notification event doesn’t suffice the requirement , in saying so we should not forget that events are means to be lightweight and hence the payload should be kept to essential fields only.
Below are some of the materials I referred to while writing this blog and can provide more insights additionally I would highly recommend going through the tutorial for event consumption scenarios . Let me know what you think of this new feature in comments below and please provide feedback.
Creating Event Consumption Model
Hi Siddhartha,
Very well explained blog on RAP with Event Mesh. Thanks for sharing!!
Thank you,
Syam
Hi Siddhartha,
Thanks for sharing this blog.
Very well explained. Thank you Siddhartha..
Hi Siddhartha Routh ,
thanks for the helpful blog!
Is it possible in Embedded Steampunk to directly/locally consume RAP Business Events, eg. an event from a S/4HANA Cloud Standard BO in an ABAP Environment based extension?
Regards,
Wolfgang
Hi , Wolf Gang , yes it is possible to RAP events outside the context of the RAP BO .
Hi Siddhartha Routh ,
thanks for the quick answer!
And how can the achieved, ie direct local consumption of an RAP business event without going through event mesh?
Regards,
Wolfgang
Wolfgang Röckelein, did you find a solution to consume the event without using the Event Mesh? We have a similar requirement to consume the event from an external client App on another SaaS platform. We need somehow to use the outbound channel that is not linked to the SAP Event Mesh but to a free HTTP endpoint where the event can be sent to that endpoint. Furthermore, for the authentication to the external App, we need OAuth2 authentication.
Somebody has an idea how to send the event to a Webhook URL? Many blogs mostly show how to push events to SAP BTP Event Mesh. But meanwhile, we have many external client Apps sitting on different Cloud platforms, and not every customer has an SAP BTP Event Mesh license.
Hi Ly-Na Phu ,
meanwhile I learned that local consumption is on the roadmap for next year.
Event Mesh can at least forward events via standard based protocols and REST APIs, cf. https://help.sap.com/docs/SAP_EM/bf82e6b26456494cbdd197057c09979f/3f424ff1ae3b4bc084c4f1ea0be96f54.html
Regards,
Wolfgang
Thanks Wolfgang Röckelein
Yes, with event mesh, we can use webhook to send the event to an endpoint. The problem is that some customers don't have an SAP Event Mesh license. They already have another Event Broker in use and don't need another event broker, such as the SAP Event Mesh in the chain. Using two event brokers in the chain is quite unnecessary.
What does local consumption mean? Does it mean that we can write our own abap class as the subscriber or event consumer and do what we want, e.g., in our code, we would use the HTTP client library to invoke an HTTP endpoint to push the event to that endpoint. That would be great.
Thanks,
Ly-Na
Hi Ly-Na Phu ,
yes, this is my understanding.
Regards,
Wolfgang
Hi Sidharta,
Great post!
Quick question on the support for dynamic topics:
Could I use the RAP approach to add data from the event into the topic that I'm publishing to?
E.g. it looks like in your example you have it configured to publish to topic:
zsap/s4/beh/Coninfo/Create/v1/
Could I append that with some dynamic fields like e.g.
zsap/s4/beh/Coninfo/Create/v1/<user lastname>/<user firstname>
To promote fields from the actual event into the topic for filtering purposes?
p.s. adding first name or last name may not be the most logical fields, but it would be useful for other fields like e.g. country codes or deparment ids in other use cases/with other business objects.
Regards,
Christian
Hi Chirstian,
I don't think you can do that.
The topic needs to be pre-defined and also the queues subscribing them needs the predefined topic to receive the message.
Regards
Sidd
Hi Siddhartha,
Is that a conscious decision to limit it to predefined/static topics in RAP?
Both SAP Event Mesh as well as SAP Advanced Event Mesh are capable of handling dynamic topics, which is one of the strength of them.
You can use wildcards in queue subscriptions if you want to match all dynamic values of a topic field. E.g. In my example above you could use:
zsap/s4/beh/Coninfo/Create/v1/>
For the multi-level wildcard (> in Solace notation) or the equivalent of # in AMQP notation.
Or you could subscribe using the single level wildcards to match precisely two levels:
zsap/s4/beh/Coninfo/Create/v1/*/*
This becomes really powerful when you e.g. have a topic level that contains a countrycode and you want to attract events for one country to one specific queue for some specific countries.
Would be great if this could be supported with the RAP approach.
Best regards,
Christian
As per your blog, Create button is not coming in App and getting error in Event Binding that SAP Object Type Coninfo does not exist.