Consuming Draft-Enabled RAP OData V4 Applications Using SAP Gateway
Share

[[{“value”:”

Introduction:

I developed a draft-enabled RAP application and exposed it as an OData V4 Web API that can be consumed by other users or applications. Since this application is exposed purely as a Web API, I did not create a Fiori application to consume and manage the RAP service.

While testing the OData V4 service manually using the SAP Gateway Client, I encountered an issue during Create, Update, and Delete operations. After performing these operations, I noticed that the changes were not immediately available in the active database table as I expected. This led me to understand how draft-enabled RAP applications behave when they are consumed directly through an OData Web API.

Step 1: Create the Service Binding

Once the Service Definition (ZUI_B_SALES) is activated, the next step is to create a Service Binding on top of it.

  1. In ADT, right-click the Service Definition ZUI_B_SALES → New Service Binding.
  2. Give it a name and description (e.g. ZSB_V4_WEB_API).
  3. Set the Binding Type to:

    ODATA V4 — Web API

  4. Finish the wizard and activate the Service Binding.

bhuvaneswarg_0-1788169098703.png

The Service Binding is now created. Activate it to make sure all related objects are activated successfully.

bhuvaneswarg_1-1788169122163.png

After opening the Service Binding, you will see the Service Binding editor. Unlike some other RAP service binding scenarios, the OData V4 Web API service cannot be published directly from this editor in ADT.

To make the OData V4 Web API available for external consumption and testing, the service must be published through the SAP Gateway. The next step explains how to publish the Service Binding using the Gateway administration transaction.

Step 2: Publish the Service via /IWFND/V4_ADMIN

Creating and activating the Service Binding in ADT generates the service, but it still needs to be published on the Gateway hub before it’s externally callable (via Fiori, Postman, /IWFND/GW_CLIENT , etc.).

  1. Run transaction /IWFND/V4_ADMIN.
  2. Click on Public Service Groups (top of the screen).
  3. Enter the System Alias as Local.
  4. Enter the Service Binding nameZSB_V4_WEB_API — and press Enter. The service should now appear in the list below.
  5. Select it and click Publish Service Group.

bhuvaneswarg_2-1788169169907.png

Once the service is published successfully, it will appear in the list along with its technical details, such as the Service ID, Version, and Service URL. This confirms that the OData V4 service has been successfully published and is now available through the SAP Gateway for testing and consumption.

bhuvaneswarg_3-1788169196989.png

Step 3: Verify the Service via /IWFND/GW_CLIENT

With the service published, we can test it directly using the Gateway Client — no need for Postman or a Fiori app at this stage.

  1. Run transaction /IWFND/GW_CLIENT.
  2. Paste the service URL into the URL bar, choose the HTTP method, and add a payload where required (details below for each operation).
  3. Verify the Available EntitySets.

bhuvaneswarg_0-1788169333115.png

Now, we can see all the exposed Entity Sets, including the additional entities related to the draft-enabled RAP application.

CRUD Operations:

Read / GET — Header with Items (Expand)

Method: GET

URL:

/sap/opu/odata4/sap/zsb_v4_web_api/srvd_a2x/sap/zui_b_sales/0001/SalesHeader?$expand=_items

$expand=_items tells OData to pull each header’s related item lines in the same response, using the _items navigation property defined on ZC_B_SALES. Without $expand, you’d only get header fields and would need a separate call per header to fetch its items.

bhuvaneswarg_1-1788169360790.png

Now, we can see all the available records from the active table. You may notice that some draft-related fields are also displayed in the response.

This might raise the question: if we are retrieving data from the active table, why are draft-related fields included?

These fields are exposed because the RAP business object is draft-enabled. RAP automatically provides additional draft-related information as part of the OData service so that the consumer can identify and manage the different states of an entity, such as its active and draft versions.

Create — Deep Create (Header + Items in One Call)

Method: POST

URL:

/sap/opu/odata4/sap/zsb_v4_web_api/srvd_a2x/sap/zui_b_sales/0001/SalesHeader

This is a deep create — because the header’s behavior definition exposes create on the _items association, we can nest the item rows directly inside the header payload’s _items array, and RAP creates the header and all its item lines together in one atomic call.

When I tried to create a new record I initially expected the data to be created successfully. However, after executing the request, I noticed that the new record was not available in the active table.

To create the record as an active entity, I added the draft-related entity information to the request payload and explicitly specified:

{ “IsActiveEntity”: true }

The same value was provided for both the header and item entities in the deep-create request.

After sending the request with the correct entity state, the record was created successfully and became available in the active table.

The following payload was used to create the header along with its associated items:

{
  "vbeln": "0000000021",
  "ernam": "Name",
  "erdat": "2026-08-10",
  "vbtyp": "A",
  "vkorg": "US01",
  "IsActiveEntity": true,
  "_items": [
    {
      "posnr": "20",
      "matnr" : "0000000005",
      "IsActiveEntity": true
    },
    {
      "posnr": "10",
      "matnr" : "0000000005",
      "IsActiveEntity": true
    }
  ]
}

on both the header and every item in the payload, exactly as shown above. Leave this out (or set it to false) if you intentionally want to create a draft first and activate/save it in a separate step later.

bhuvaneswarg_0-1788174069306.png

Delete — Header (Cascades to Items)

Method: DELETE

URL:

/sap/opu/odata4/sap/zsb_v4_web_api/srvd_a2x/sap/zui_b_sales/0001/SalesHeader(vbeln=’0000000003′,IsActiveEntity=true)

Deleting a header record deletes all of its associated item records as well, since items exist only as dependents of a header (this cascade behavior comes from the composition/association defined between ZC_B_SALES and ZC_B_ITEMS).

bhuvaneswarg_0-1788174245489.png

Delete — Single Item Only

Method: DELETE

URL:

/sap/opu/odata4/sap/zsb_v4_web_api/srvd_a2x/sap/zui_b_sales/0001/SalesItem(vbeln=’0000000021′,posnr=’000010′,IsActiveEntity=true)

bhuvaneswarg_1-1788174352983.png

Use this when you want to remove just one item line without touching the header or the other items under it. Note the item’s composite key — both vbeln (parent) and posnr (item number) are required to address a single item uniquely.

Update — Header and Item Together (Batch / $batch)

OData V4 doesn’t let you update two different entity sets (header and item) in a single plain PATCH request. To update both atomically — meaning either both changes succeed, or neither does — you send a $batch request containing a changeset.

Method: POST

URL:

/sap/opu/odata4/sap/zsb_v4_web_api/srvd_a2x/sap/zui_b_sales/0001/$batch

Critical: The outer request itself (in the Gateway Client’s request header section, not the body) must carry:

Content-Type: multipart/mixed; boundary=batch

This must match the --batch boundary string used in the body below. If this is missing or mismatched, or if any line in the body has leading whitespace, you’ll get an /IWCOR/CX_OD_BATCH_PAYLOAD “Batch request payload is invalid” error — the parser is very strict about multipart formatting

Payload:

–batch
Content-Type: multipart/mixed; boundary=changeset

–changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

PATCH SalesHeader(vbeln=’0000000009′,IsActiveEntity=true) HTTP/1.1
Content-Type: application/json
Accept: application/json
If-Match: *

{
“ernam”: “BGURIJALA”,
“erdat”: “2026-08-11”,
“vbtyp”: “B”,
“vkorg”: “US01”
}

–changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

PATCH SalesItem(vbeln=’0000000009′,posnr=’20’,IsActiveEntity=true) HTTP/1.1
Content-Type: application/json
Accept: application/json
If-Match: *

{
“matnr”: “0000000005”,
“charg”: “01”,
“matkl”: “01”
}

–changeset–
–batch–

bhuvaneswarg_0-1788175070546.png

Conclusion: 

When a RAP application is exposed as a plain OData V4 Web API — without a Fiori app in front of it — there’s no automatic help managing drafts. You have to tell the service yourself whether you’re working with a draft or the final saved data, and that’s what the IsActiveEntity field is for.

In simple terms:

  • IsActiveEntity = false → this is a draft, a temporary version that hasn’t been saved yet.
  • IsActiveEntity = true → this is the active, final version of the data.

Once you remember to set this field correctly on every Create, Update, or Delete request, the confusing part goes away — your changes show up where you expect them to, and the service behaves consistently. This one field is really the key to working with draft-enabled RAP services manually through SAP Gateway.

 

“}]] 

  Read More Technology Blog Posts by Members articles 

#abap

By ali

Leave a Reply