Technical Articles
Batch operation in in OData V4 Adapter in SAP Cloud Integration
In this post you will be able to learn how to integrate an OData V4 system through SAP Cloud Integration using $batch method. The OData V4 adapter now provides support for $batch operation. This method is very useful when you need to perform multiple requests. As the name suggests this operation helps you to club multiple HTTP requests into one request. This will result in improved performance for the same.
At present, the OData adapter supports the following OData operations
- GET (Query)
- POST (Create)
- PUT(Update)
- DELETE (Delete)
- FUNCTION IMPORT
Configuring Batch in OData V4 Adapter
We will be using the OData Demo V4 service, http://services.odata.org/(S(btmy2xygehkm1gfrnpezr4xx))/V4/OData/OData.svc in this example.
To model a batch operation you will have to select the “Batch Processing ($batch)” option as the Operation in the processing tab of the adapter
To model the batch scenario click on the “Select” button to open the querybuilder dialog. Once the dialog opens provide the connection information as shown below.
After you click on “Step 2” button you will be presented with the “Select Entity and DefineOperation” screen as shown below.
Click on “Add ChangeSet” to to add a changeset which will include a “batchChangeSetPart” section. ChangeSets are used for place data modification request such as “POST/PUT/DELETE”. For Data Retrieval requests you can click on “Add Batchset” to add batchset. For You can add more ChangeSetParts to a ChangeSet using “+” icons. Each ChangeSetPart or BatchSet will contain an entity. You can change the entity for which you want to model the requests. Below the table you will be able to specify the name for the XSD schema file which will be generated for this model. The XSD file which will be generated once the Finish button is clicked.
This XSD schema will define the input payload for the batch operation. You can use the XSD schema to validate the payload by putting a mapping step before the OData V4 adapter.
Let us examine the different type of payloads required for different operations.
Request Payload formats
The supported input type to the OData V4 adapter is xml at present. The xml payload is converted to json in case of non-batch operations and multipart/mixed format in case of batch operations by the adapter.
For the batch operation the input xml should be enclosed within a “batchParts” tag. It can contain any number of “batchSets” and “batchChangeSet” tags according to the requirements. The “batchChangeSet” tag can contain any number of “batchChangeSetPart” tags inside “batchChangeSet” tag.
Each “batchSet” and “batchChangeSetPart” tag should contain the following tags for one http request
- method : This is a mandatory tag. Should contain values of the HTTP operation such as GET, PUT, POST, DELETE, FUNCTION_IMPORT
- uri : This is a mandatory tag which should specify the relative url of the HTTP call to the service url.
- headers : This is an optional field, It can contain any custom headers required for the specific HTTP call.
- body : This is an optional field, This is required for PUT and POST operations, where the payload for an entity has to be specified.
Response Payload Formats
The output of the Odata V4 adapter is also in XML format. The output xml will be enclosed within a “batchPartsResponse” tag. Each “batchSet” will have a corresponding “batchSetResponse” and each “batchChangeSet” and “batchChangeSetPart” will have a “batchChangeSetResponse” and “batchChangeSetPartResponse” sections. Each response section will have the following sections
- statusInfo: The HTTP status of the request.
- statusCode: The HTTP response code of the request.
- body: The response body of the request will be contained in this section.
- headers : The response headers of the HTTP request.
Here are some example request and response payloads for different operations.
POST
Sample Request
<batchParts>
<batchChangeSet1>
<batchChangeSetPart1>
<method>POST</method>
<uri>Products</uri>
<body>
<Products>
<Product>
<ID>101</ID>
<Name>Macbook pro</Name>
<ReleaseDate>2019-01-01T00:00:00Z</ReleaseDate>
<Rating>5</Rating>
<Price>1500</Price>
</Product>
</Products>
</body>
</batchChangeSetPart1>
<batchChangeSetPart2>
<method>POST</method>
<uri>Categories</uri>
<body>
<Categories>
<Category>
<ID>101</ID>
<Name>Laptops</Name>
</Category>
</Categories>
</body>
</batchChangeSetPart2>
</batchChangeSet1>
</batchParts>
Sample Response
<?xml version='1.0' encoding='UTF-8'?>
<batchPartsResponse>
<batchChangeSetResponse>
<batchChangeSetPartResponse>
<headers>
<header>
<headerName>Cache-Control</headerName>
<headerValue>no-cache</headerValue>
</header>
<header>
<headerName>Content-Type</headerName>
<headerValue>application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=false;charset=utf-8</headerValue>
</header>
<header>
<headerName>Location</headerName>
<headerValue>https://services.odata.org/V4/OData/(S(CPI_batch_abc))/OData.svc/Products(101)</headerValue>
</header>
<header>
<headerName>OData-Version</headerName>
<headerValue>4.0;</headerValue>
</header>
<header>
<headerName>X-Content-Type-Options</headerName>
<headerValue>nosniff</headerValue>
</header>
</headers>
<statusInfo>Created</statusInfo>
<body>
<Products>
<Product>
<Description/>
<Price>1500.0</Price>
<Rating>5</Rating>
<DiscontinuedDate/>
<ID>101</ID>
<ReleaseDate>2019-01-01T00:00:00Z</ReleaseDate>
<Name>Macbook pro</Name>
</Product>
</Products>
</body>
<statusCode>201</statusCode>
</batchChangeSetPartResponse>
<batchChangeSetPartResponse>
<headers>
<header>
<headerName>Cache-Control</headerName>
<headerValue>no-cache</headerValue>
</header>
<header>
<headerName>Content-Type</headerName>
<headerValue>application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=false;charset=utf-8</headerValue>
</header>
<header>
<headerName>Location</headerName>
<headerValue>https://services.odata.org/V4/OData/(S(CPI_batch_abc))/OData.svc/Categories(101)</headerValue>
</header>
<header>
<headerName>OData-Version</headerName>
<headerValue>4.0;</headerValue>
</header>
<header>
<headerName>X-Content-Type-Options</headerName>
<headerValue>nosniff</headerValue>
</header>
</headers>
<statusInfo>Created</statusInfo>
<body>
<Categories>
<Category>
<ID>101</ID>
<Name>Laptops</Name>
</Category>
</Categories>
</body>
<statusCode>201</statusCode>
</batchChangeSetPartResponse>
</batchChangeSetResponse>
</batchPartsResponse>
GET operation
Sample Request
<batchParts>
<batchSet1>
<method>GET</method>
<uri>Products(101)</uri>
<headers>
<header>
<headerName>Accept</headerName>
<headerValue>application/json;odata.metadata=minimal</headerValue>
</header>
</headers>
</batchSet1>
<batchSet2>
<method>GET</method>
<uri>Categories(101)</uri>
<headers>
<header>
<headerName>Accept</headerName>
<headerValue>application/json;odata.metadata=minimal</headerValue>
</header>
</headers>
</batchSet2>
</batchParts>
Sample Response
<?xml version='1.0' encoding='UTF-8'?>
<batchPartsResponse>
<batchSetResponse>
<headers>
<header>
<headerName>Cache-Control</headerName>
<headerValue>no-cache</headerValue>
</header>
<header>
<headerName>Content-Type</headerName>
<headerValue>application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8</headerValue>
</header>
<header>
<headerName>OData-Version</headerName>
<headerValue>4.0;</headerValue>
</header>
<header>
<headerName>X-Content-Type-Options</headerName>
<headerValue>nosniff</headerValue>
</header>
</headers>
<statusInfo>OK</statusInfo>
<body>
<Products>
<Product>
<Description/>
<Price>1500.0</Price>
<Rating>5</Rating>
<DiscontinuedDate/>
<ID>101</ID>
<ReleaseDate>2019-01-01T00:00:00Z</ReleaseDate>
<Name>Macbook pro</Name>
</Product>
</Products>
</body>
<statusCode>200</statusCode>
</batchSetResponse>
<batchSetResponse>
<headers>
<header>
<headerName>Cache-Control</headerName>
<headerValue>no-cache</headerValue>
</header>
<header>
<headerName>Content-Type</headerName>
<headerValue>application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8</headerValue>
</header>
<header>
<headerName>OData-Version</headerName>
<headerValue>4.0;</headerValue>
</header>
<header>
<headerName>X-Content-Type-Options</headerName>
<headerValue>nosniff</headerValue>
</header>
</headers>
<statusInfo>OK</statusInfo>
<body>
<Categories>
<Category>
<ID>101</ID>
<Name>Laptops</Name>
</Category>
</Categories>
</body>
<statusCode>200</statusCode>
</batchSetResponse>
</batchPartsResponse>
UPDATE
Sample request
<batchParts>
<batchChangeSet1>
<batchChangeSetPart1>
<method>PUT</method>
<uri>Products(101)</uri>
<body>
<Products>
<Product>
<ID>101</ID>
<Name>Macbook pro</Name>
<ReleaseDate>2019-01-01T00:00:00Z</ReleaseDate>
<Rating>4</Rating>
<Price>2000</Price>
</Product>
</Products>
</body>
</batchChangeSetPart1>
<batchChangeSetPart2>
<method>PUT</method>
<uri>Categories(101)</uri>
<body>
<Categories>
<Category>
<ID>101</ID>
<Name>Laptops and Chromebooks</Name>
</Category>
</Categories>
</body>
</batchChangeSetPart2>
</batchChangeSet1>
</batchParts>
Sample Response
<?xml version='1.0' encoding='UTF-8'?>
<batchPartsResponse>
<batchChangeSetResponse>
<batchChangeSetPartResponse>
<headers>
<header>
<headerName>Cache-Control</headerName>
<headerValue>no-cache</headerValue>
</header>
<header>
<headerName>OData-Version</headerName>
<headerValue>4.0;</headerValue>
</header>
<header>
<headerName>X-Content-Type-Options</headerName>
<headerValue>nosniff</headerValue>
</header>
</headers>
<statusInfo>No Content</statusInfo>
<statusCode>204</statusCode>
</batchChangeSetPartResponse>
<batchChangeSetPartResponse>
<headers>
<header>
<headerName>Cache-Control</headerName>
<headerValue>no-cache</headerValue>
</header>
<header>
<headerName>OData-Version</headerName>
<headerValue>4.0;</headerValue>
</header>
<header>
<headerName>X-Content-Type-Options</headerName>
<headerValue>nosniff</headerValue>
</header>
</headers>
<statusInfo>No Content</statusInfo>
<statusCode>204</statusCode>
</batchChangeSetPartResponse>
</batchChangeSetResponse>
</batchPartsResponse>
DELETE
Sample Request
<batchParts>
<batchChangeSet1>
<batchChangeSetPart1>
<method>DELETE</method>
<uri>Products(101)</uri>
</batchChangeSetPart1>
<batchChangeSetPart2>
<method>DELETE</method>
<uri>Categories(101)</uri>
</batchChangeSetPart2>
</batchChangeSet1>
</batchParts>
Sample Response
<?xml version='1.0' encoding='UTF-8'?>
<batchPartsResponse>
<batchChangeSetResponse>
<batchChangeSetPartResponse>
<headers>
<header>
<headerName>Cache-Control</headerName>
<headerValue>no-cache</headerValue>
</header>
<header>
<headerName>OData-Version</headerName>
<headerValue>4.0;</headerValue>
</header>
<header>
<headerName>X-Content-Type-Options</headerName>
<headerValue>nosniff</headerValue>
</header>
</headers>
<statusInfo>No Content</statusInfo>
<statusCode>204</statusCode>
</batchChangeSetPartResponse>
<batchChangeSetPartResponse>
<headers>
<header>
<headerName>Cache-Control</headerName>
<headerValue>no-cache</headerValue>
</header>
<header>
<headerName>OData-Version</headerName>
<headerValue>4.0;</headerValue>
</header>
<header>
<headerName>X-Content-Type-Options</headerName>
<headerValue>nosniff</headerValue>
</header>
</headers>
<statusInfo>No Content</statusInfo>
<statusCode>204</statusCode>
</batchChangeSetPartResponse>
</batchChangeSetResponse>
</batchPartsResponse>
Function Import
Sample Request
<?xml version="1.0" encoding="UTF-8"?>
<batchParts>
<batchSet1>
<method>FUNCTION_IMPORT</method>
<uri>GetNearestAirport(lon=-118,lat=33)</uri>
<headers>
<header>
<headerName>Accept</headerName>
<headerValue>application/json;odata.metadata=minimal</headerValue>
</header>
</headers>
</batchSet1>
</batchParts>
Sample Response
<?xml version='1.0' encoding='UTF-8'?>
<batchPartsResponse>
<batchSetResponse>
<headers>
<header>
<headerName>Content-Type</headerName>
<headerValue>application/json; odata.metadata=minimal</headerValue>
</header>
<header>
<headerName>OData-Version</headerName>
<headerValue>4.0</headerValue>
</header>
</headers>
<statusInfo>OK</statusInfo>
<body>
<Airports>
<Airport>
<IataCode>LAX</IataCode>
<IcaoCode>KLAX</IcaoCode>
<Name>Los Angeles International Airport</Name>
<Location>
<Address>1 World Way, Los Angeles, CA, 90045</Address>
<Loc>GEOGRAPHY'SRID=4326;Point(-118.408055555556 33.9425)'</Loc>
<City>
<Name>Los Angeles</Name>
<CountryRegion>United States</CountryRegion>
<Region>California</Region>
</City>
</Location>
</Airport>
</Airports>
</body>
<statusCode>200</statusCode>
</batchSetResponse>
</batchPartsResponse>
Hi BipLob,
Interesting blog! Just one question, the Odata V4 Receiver adapter does not have ''FUNCTION IMPORT' Odata Operation, in my case only this case it's possible:
How do you define de Function Import?
Thanks & Regards,
Elisa
Hi Elisa,
The OData V4 adapter does not support Function Imports as a separate method as of now. It will be available in a future release.
However, you can use the Batch Processing method for invoking function imports. In a batch call you can club multiple OData requests. One or more calls in the request can be a function import call. The example for Function Import in $batch method is listed in the last section. You have to select "Batch Processing" option for that.
Regards
Biplob
Hi Biplob,
it's now two years later. Does the OData V4 adapter now supports Function Imports as a separate method? Or is there at least a roadmap item?
Best Regards
Gregor
Hi Gregor,
Function Imports are not yet supported by the OData V4 adapter as a separate method. However, this is in the roadmap. However, this will be prioritised according to the customer demand for this particular feature.
I will alert the product management team of your interest in the feature.
Regards
Biplob
Hi Biplob,
thank you for your reply. I can't understand that this feature is missing in the V4 adapter as it is available in V2. In our case we use Cloud Integration to replicate data that is provided from a standard S/4HANA service to a CAP application. By default CAP supports OData V4. To make our integration work I needed to add the OData V2 Proxy.
Best Regards
Gregor
Hi Gregor,
SAP has introduced SAP influence to allow Customer to provide feedback and requirements. Please refer the blog post for more details. https://blogs.sap.com/2020/05/29/central-sap-cloud-platform-feedback-requirements-channel-for-customers-and-partner-now-available/
You can submit your request in SAP Influence for the benefit of better visibility and updates from product management team.
Regards
Biplob
Hi Biplop,
I'm well aware of the SAP Influencing program. I've filed now the influencing request:
Add support for Function Imports to the OData V4 Adapter
Best Regards
Gregor
Hi Biplob
Thank you for examples in your blog!
I'm currently facing another issue.
When I create a batch (see below Batch input) only the last Businesspartner is created (see below Batch output.xml).
Batch input xml
Batch Output XML
As you can see only the last 1 is created.
Can you help me?
Thanks in advance.
Lars
Hi Lars,
You are trying to insert two entities in one batchchangesetpart. You should create a second batchchangesetpart for the second entity.
Regards
Biplob
Hello,
Where should I use the Function Import's XML?
It's not clear.
Att.,
Vinicius
Hi Biplob,
Thanks for the blog!
Hi Biplob,
I have a question, is it possible to emulate JDBC Option : Atomic and not Atomic?
Federico Bellizia