SAP CAP: Working with eTags

In this SAP Note, I’d like to describe what an eTag is and how this mechanism can be leveraged in CAP projects.

What is CAP?

Introduction to CAP | capire
Documentation for SAP Cloud Application Programming Model
The Cloud Application Programming Model (CAP) is a framework of languages, libraries, and tools for building enterprise-grade cloud applications. It guides developers along a golden path of proven best practices, which are served out of the box by generic providers cloud-natively, thereby relieving application developers from tedious recurring tasks.

What is an eTag?

eTag stands for Entity Tag and is used in OData services to track the version of an entity entry. In SAP CAP, you mark a property (usually a timestamp or version field) with the @odata.etag annotation, enabling version control at the API level.

Providing Services | capire
Documentation for SAP Cloud Application Programming Model

Technically, eTags are part of the HTTP specification and are used to implement optimistic concurrency control. More details can be found in the HTTP spec:

ETag - HTTP | MDN
The HTTP ETag (entity tag) response header is an identifier for a specific version of a resource. It lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content has not changed. Additionally, ETags help to prevent simultaneous updates of a resource from overwriting each other (“mid-air collisions”).

Why would I need to use an eTag in my project?

Using eTags helps prevent data inconsistencies when multiple users or systems interact with the same entity.

Let’s say your application manages news posts. As a chief editor, you notice a grammar mistake and decide to fix it. You open the post, make your correction, and hit Save. But—suddenly—you get the error:

The post/article/order... has been updated. Please refresh the page

You refresh the page and notice that the changes have already been made—someone else updated the post before you.

This is where eTags come into play: they detect whether the entry was modified since you last fetched it, thus avoiding unintentional overwrites.

Let’s now look under the hood and implement a basic CAP scenario to demonstrate eTag behavior.

Scenario

In this note, I’ll walk through a simple example: creating a CAP service that stores news posts and uses eTags to detect concurrent updates.

Initial setup

Refer to this guide to set up a basic CAP project:

Getting Started | capire
Documentation for SAP Cloud Application Programming Model

Create a new folder and initialize the CAP project

Create a new folder for your project by running the following command (in the example below, proj2 is the name of the folder where all the project files will reside).

cds init proj2

Define a Domain Model for your project

In our example, we’ll model a simple news feed. Create a new file named schema.cds inside the db folder with the following content:

namespace sap.localhost.newsintranet;

entity News {
    key ID         : Integer;
        news_title : localized String(200);
        news_body  : localized String;

        @odata.etag
        editedAt   : Timestamp
}

Define a Service for the Model

Create a service.cds file inside the srv folder:

using {sap.localhost.newsintranet as news} from '../db/schema';

service NewsService {
    entity News as projection on news.News;
}

Run the service

To run your service locally:

cds watch

Then open http://localhost:4004 in your browser. You’ll see the CAP admin UI. Click the News Service endpoint to inspect your entity:

Add Mock Data

Let’s add data to your service by running the command below in the terminal.

cds add data

This will generate a data folder under db and a .csv file for your entity. Populate the CSV with some test records.

Once saved and deployed, refresh your browser—your test entries should now be visible.

You can also access individual entries:

GET http://localhost:4004/odata/v4/news/News(1)

Check the terminal for logs—it often provides helpful insights or warnings.

What About eTags?

Let’s dive into the main topic: how to use the eTag value. Open Postman, send a GET request to your service, e.g.:

In the response body, you’ll see the @odata.etag field. In the response headers, locate the ETag value—it represents the current version of the entity.

How to Use the eTag Value (1)

Now, let’s simulate an update. Copy the ETag value from the GET response

Add the If-Match header with the copied eTag value.

Add your update payload:

Click Send:

You should receive a 200 OK response. This means the entity was updated because the eTag matched the server's current version.

💡
CAP handles the ETag validation behind the scenes — as long as you provide the correct If-Match header, CAP will automatically determine whether the update should proceed based on whether the record has been modified. You don’t need to implement custom logic for this check.

How to Use the eTag Value (2)

Now let’s test a conflict. Manually change the editedAt value in your CSV file for a given record (e.g., from 2025-01-02T23:56:00Z to 2025-01-02T23:57:00Z)

Use Postman to send a PATCH request with the old eTag in the If-Match header:

You’ll get a 412 Precondition Failed response:

412 Precondition Failed - HTTP | MDN
The HTTP 412 Precondition Failed client error response status code indicates that access to the target resource was denied. This happens with conditional requests on methods other than GET or HEAD when the condition defined by the If-Unmodified-Since or If-Match headers is not fulfilled. In that case, the request (usually an upload or a modification of a resource) cannot be made and this error response is sent back.

This response tells you that the record has changed, and your update was blocked to avoid overwriting new data. To proceed, you’d need to GET the latest eTag again and retry your update.

This was a long one—but I hope it clarified how eTags work in SAP CAP and how you can use them to protect your data from concurrency issues.

I plan to continue exploring CAP topics and sharing tips that might be helpful for real-world projects. Cheers!