ETag In RAP

Estimated read time 13 min read

This blog post provides a beginner-friendly introduction to the concept of ETags in RAP (RESTful ABAP Programming). 

Introduction 

This is one of the concurrency control approaches 

ETag is used to manage data concurrency, preventing multiple users from overwriting the same record simultaneously, similar to the functionality of lock objects. 

Concurrency: Accessing/Updating a resource at the same time by different users. It causes confusion among the users and inconsistency in the excepted output. 

If you use Etag, so multiple user can only read the data but they can’t update the data, because the server first check the Etag value. 

Scenario for Etag in RAP 

Consider a scenario where two users access the same record, and User 1 saves their changes first, the ETag mechanism ensures User 2 cannot overwrite those changes without being aware of the update. This prevents data inconsistencies. In this blog, we’ll explore implementing ETag functionality in RAP using a timestamp field. 

Procedure: 

1. Created one database table ‘ZVS_DT_TRAVEL’. 

The table zvs_dt_travel holds information related to travel records. It includes key fields like travel_id, and non-key fields such as agency_id, begin_date, end_date, last_changed_by, and last_changed_at. The field last_changed_at is particularly important because it tracks the last timestamp when the record was modified. This timestamp will be used to generate the ETag value.

 

@EndUserText.label : ‘Table for travel’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zvs_dt_travel {

key client : abap.clnt not null;
key travel_id : /dmo/travel_id not null;
agency_id : /dmo/agency_id;
begin_date : /dmo/begin_date;
end_date : /dmo/end_date;
last_changed_by : abp_locinst_lastchange_user;
last_changed_at : abp_locinst_lastchange_tstmpl;

}

 

This table holds travel records:

2. Now create one interface view ‘ZVS_I_TRAVEL1’ on top of DB table: – 

The CDS interface view zvs_i_travel1 selects the relevant fields from the zvs_dt_travel table, including last_changed_at. This field (last_changed_at) will be used for generating the ETag value, as indicated by the @Semantics.systemDateTime.localInstanceLastChangedAt annotation. This annotation ensures that last_changed_at is recognized as the field that tracks the last modification time. 

Code of interface view: 

 

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘interface view for travel’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define root view entity zvs_i_travel1 as select from zvs_dt_travel
{
key travel_id as TravelId,
agency_id as AgencyId,
begin_date as BeginDate,
end_date as EndDate,
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.localInstanceLastChangedAt: true //annotation marks LastChangedAt as the timestamp for enabling ETag checks.
last_changed_at as LastChangedAt
}

 

ETag Generation: The last_changed_at field will act as the ETag value. The ETag is a unique identifier for the version of the record. Whenever the last_changed_at value changes (which happens when a record is updated), the ETag value will also change. 

3. Now create on consumption view ‘ZVS_C_TRAVEL1’ on top of interface view: 

The consumption view zvs_c_travel1 projects the data from the interface view zvs_i_travel1. This view is intended to expose the data for transactional operations, such as create, update, and delete. The consumption view allows clients to interact with the data, but the actual persistence and behavior are managed through the behavior definition. 

Code of Projection view: 

 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption view for travel’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define root view entity zvs_c_travel1
provider contract transactional_query
as projection on zvs_i_travel1
{
key TravelId,
AgencyId,
BeginDate,
EndDate,
LastChangedBy,
LastChangedAt
}

 

4. Now create a behavior definition on top of interface view: 

In the behavior definition for zvs_i_travel1, the LastChangedAt field is specified as the ETag for concurrency control. It is marked as the etag master LastChangedAt, ensuring that the value of LastChangedAt will be used for update validation. 

Update Scenario: When a client sends an UPDATE request, it must include the If-Match header containing the LastChangedAt timestamp (the ETag value). The system will check this value against the current LastChangedAt value stored in the database. If the values match, the update will proceed. If the values don’t match (meaning the record has been updated by another user), the system will return a 412 Precondition Failed error, preventing the overwrite. 

Code of Behavior Definition of Interface: 

 

managed implementation in class zbp_vs_i_travel1 unique;
strict ( 2 );

define behavior for zvs_i_travel1 //alias <alias_name>
persistent table zvs_dt_travel
lock master
authorization master ( instance )
etag master LastChangedAt //ensures concurrency control using the LastChangedAt field for ETag verification
{
create;
update;
delete;
field ( readonly ) TravelId;

mapping for zvs_dt_travel{
TravelId = travel_id;
AgencyId = agency_id;
BeginDate = begin_date;
EndDate = end_date;
LastChangedBy = last_changed_by;
LastChangedAt = last_changed_at;
}

}

 

5. Now create a behavior definition on top of consumption view: 

In the behavior definition for the consumption view (zvs_c_travel1), you must specify that ETag should be used. This tells RAP that the consumption view will work with ETags when performing operations like create, update, or delete. 

ETag Use: This line ensures that ETag will be used during the create, update, and delete operations. It tells RAP that when a record is updated, the ETag value (i.e., LastChangedAt) should be checked to prevent overwriting concurrent changes. 

Code of Behavior Definition of Projection: 

 

projection;
strict ( 2 );

define behavior for zvs_c_travel1 alias travel
use etag //ensures ETag validation during create, update, and delete operations
{
use create;
use update;
use delete;
}

 

ETag Mechanism in Updating Data: 

When the client wants to update the travel record, it sends a PATCH request to the system with the If-Match header containing the ETag value (i.e., the LastChangedAt value). The system will compare the If-Match value with the current LastChangedAt value in the database. 

If the If-Match value matches the current LastChangedAt, the update is allowed, and the LastChangedAt is updated to the current timestamp. If the If-Match value doesn’t match the current LastChangedAt (i.e., the record has been modified by another user in the meantime), the update is rejected, and the system returns a 412 Precondition Failed error. 

Now from the Frontend, two different users are accessing the same data at the same time: 

User 1: 

User 2: 

Now user 1 will change the End Date: 

 

Here we can see that User 1 updated the data successfully.

But here User 2, still viewing the old version (Jan 8, 2025) 

Now User 2 will change End Date to Aug 5, 2025: 

So if user 2 click on save button, so he will get one error: – 

(Your changes could not be saved. A more recent version is available. To make changes to the latest version, please refresh the data).

User 2 cannot overwrite User 1’s updated record without refreshing to see the latest changes. 

if User 1 updates a record and saves it, User 2, still viewing the old version, cannot overwrite the updated record without refreshing the data. The ETag, generated using a timestamp, ensures only the latest version can be updated, avoiding data inconsistencies.

If User 2 refreshes the data, they will be able to see the updated version and then update the data. 

After refreshing: 

Now, if User 2 tries to update the data, they can update it: 

Conclusion: 

ETag in RAP ensures data consistency by using a unique value, like a timestamp, to track changes. It prevents users from accidentally overwriting each other’s updates. 

 

 

​ This blog post provides a beginner-friendly introduction to the concept of ETags in RAP (RESTful ABAP Programming). Introduction This is one of the concurrency control approaches ETag is used to manage data concurrency, preventing multiple users from overwriting the same record simultaneously, similar to the functionality of lock objects. Concurrency: Accessing/Updating a resource at the same time by different users. It causes confusion among the users and inconsistency in the excepted output. If you use Etag, so multiple user can only read the data but they can’t update the data, because the server first check the Etag value. Scenario for Etag in RAP Consider a scenario where two users access the same record, and User 1 saves their changes first, the ETag mechanism ensures User 2 cannot overwrite those changes without being aware of the update. This prevents data inconsistencies. In this blog, we’ll explore implementing ETag functionality in RAP using a timestamp field. Procedure: 1. Created one database table ‘ZVS_DT_TRAVEL’. The table zvs_dt_travel holds information related to travel records. It includes key fields like travel_id, and non-key fields such as agency_id, begin_date, end_date, last_changed_by, and last_changed_at. The field last_changed_at is particularly important because it tracks the last timestamp when the record was modified. This timestamp will be used to generate the ETag value. @EndUserText.label : ‘Table for travel’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zvs_dt_travel {

key client : abap.clnt not null;
key travel_id : /dmo/travel_id not null;
agency_id : /dmo/agency_id;
begin_date : /dmo/begin_date;
end_date : /dmo/end_date;
last_changed_by : abp_locinst_lastchange_user;
last_changed_at : abp_locinst_lastchange_tstmpl;

} This table holds travel records:2. Now create one interface view ‘ZVS_I_TRAVEL1’ on top of DB table: – The CDS interface view zvs_i_travel1 selects the relevant fields from the zvs_dt_travel table, including last_changed_at. This field (last_changed_at) will be used for generating the ETag value, as indicated by the @Semantics.systemDateTime.localInstanceLastChangedAt annotation. This annotation ensures that last_changed_at is recognized as the field that tracks the last modification time. Code of interface view:  @AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘interface view for travel’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define root view entity zvs_i_travel1 as select from zvs_dt_travel
{
key travel_id as TravelId,
agency_id as AgencyId,
begin_date as BeginDate,
end_date as EndDate,
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.localInstanceLastChangedAt: true //annotation marks LastChangedAt as the timestamp for enabling ETag checks.
last_changed_at as LastChangedAt
} ETag Generation: The last_changed_at field will act as the ETag value. The ETag is a unique identifier for the version of the record. Whenever the last_changed_at value changes (which happens when a record is updated), the ETag value will also change. 3. Now create on consumption view ‘ZVS_C_TRAVEL1’ on top of interface view: The consumption view zvs_c_travel1 projects the data from the interface view zvs_i_travel1. This view is intended to expose the data for transactional operations, such as create, update, and delete. The consumption view allows clients to interact with the data, but the actual persistence and behavior are managed through the behavior definition. Code of Projection view:  @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption view for travel’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define root view entity zvs_c_travel1
provider contract transactional_query
as projection on zvs_i_travel1
{
key TravelId,
AgencyId,
BeginDate,
EndDate,
LastChangedBy,
LastChangedAt
} 4. Now create a behavior definition on top of interface view: In the behavior definition for zvs_i_travel1, the LastChangedAt field is specified as the ETag for concurrency control. It is marked as the etag master LastChangedAt, ensuring that the value of LastChangedAt will be used for update validation. Update Scenario: When a client sends an UPDATE request, it must include the If-Match header containing the LastChangedAt timestamp (the ETag value). The system will check this value against the current LastChangedAt value stored in the database. If the values match, the update will proceed. If the values don’t match (meaning the record has been updated by another user), the system will return a 412 Precondition Failed error, preventing the overwrite. Code of Behavior Definition of Interface:  managed implementation in class zbp_vs_i_travel1 unique;
strict ( 2 );

define behavior for zvs_i_travel1 //alias <alias_name>
persistent table zvs_dt_travel
lock master
authorization master ( instance )
etag master LastChangedAt //ensures concurrency control using the LastChangedAt field for ETag verification
{
create;
update;
delete;
field ( readonly ) TravelId;

mapping for zvs_dt_travel{
TravelId = travel_id;
AgencyId = agency_id;
BeginDate = begin_date;
EndDate = end_date;
LastChangedBy = last_changed_by;
LastChangedAt = last_changed_at;
}

} 5. Now create a behavior definition on top of consumption view: In the behavior definition for the consumption view (zvs_c_travel1), you must specify that ETag should be used. This tells RAP that the consumption view will work with ETags when performing operations like create, update, or delete. ETag Use: This line ensures that ETag will be used during the create, update, and delete operations. It tells RAP that when a record is updated, the ETag value (i.e., LastChangedAt) should be checked to prevent overwriting concurrent changes. Code of Behavior Definition of Projection:  projection;
strict ( 2 );

define behavior for zvs_c_travel1 alias travel
use etag //ensures ETag validation during create, update, and delete operations
{
use create;
use update;
use delete;
} ETag Mechanism in Updating Data: When the client wants to update the travel record, it sends a PATCH request to the system with the If-Match header containing the ETag value (i.e., the LastChangedAt value). The system will compare the If-Match value with the current LastChangedAt value in the database. If the If-Match value matches the current LastChangedAt, the update is allowed, and the LastChangedAt is updated to the current timestamp. If the If-Match value doesn’t match the current LastChangedAt (i.e., the record has been modified by another user in the meantime), the update is rejected, and the system returns a 412 Precondition Failed error. Now from the Frontend, two different users are accessing the same data at the same time: User 1: User 2: Now user 1 will change the End Date:  Here we can see that User 1 updated the data successfully.But here User 2, still viewing the old version (Jan 8, 2025) Now User 2 will change End Date to Aug 5, 2025: So if user 2 click on save button, so he will get one error: – (Your changes could not be saved. A more recent version is available. To make changes to the latest version, please refresh the data).User 2 cannot overwrite User 1’s updated record without refreshing to see the latest changes. if User 1 updates a record and saves it, User 2, still viewing the old version, cannot overwrite the updated record without refreshing the data. The ETag, generated using a timestamp, ensures only the latest version can be updated, avoiding data inconsistencies.If User 2 refreshes the data, they will be able to see the updated version and then update the data. After refreshing: Now, if User 2 tries to update the data, they can update it: Conclusion: ETag in RAP ensures data consistency by using a unique value, like a timestamp, to track changes. It prevents users from accidentally overwriting each other’s updates.     Read More Application Development Blog Posts articles 

#SAP

You May Also Like

More From Author