Skip to Content
Technical Articles
Author's profile photo Biplob Ghosh

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

  1. GET (Query)
  2. POST (Create)
  3. PUT(Update)
  4. DELETE (Delete)
  5. 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

  1. method : This is a mandatory tag. Should contain values of the HTTP operation such as GET, PUT, POST, DELETE, FUNCTION_IMPORT
  2. uri : This is a mandatory tag which should specify the relative url of the HTTP call to the service url.
  3. headers : This is an optional field, It can contain any custom headers required for the specific HTTP call.
  4. 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

  1. statusInfo: The HTTP status of the request.
  2. statusCode: The HTTP response code of the request.
  3. body: The response body of the request will be contained in this section.
  4. 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>

Assigned Tags

      10 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Elisa Martinez Real
      Elisa Martinez Real

      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:

      • GET (Query)
      • POST (Create)
      • PUT(Update)
      • DELETE (Delete)
      • Batch Processing

      SAP%20CPI

       

      How do you define de Function Import?

       

      Thanks & Regards,

      Elisa

      Author's profile photo Biplob Ghosh
      Biplob Ghosh
      Blog Post Author

      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

      Author's profile photo Gregor Wolf
      Gregor Wolf

      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

      Author's profile photo Biplob Ghosh
      Biplob Ghosh
      Blog Post Author

      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

      Author's profile photo Gregor Wolf
      Gregor Wolf

      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

      Author's profile photo Biplob Ghosh
      Biplob Ghosh
      Blog Post Author

      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

      Author's profile photo Gregor Wolf
      Gregor Wolf

      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

      Author's profile photo Lars Vlyminckx
      Lars Vlyminckx

      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

      <batchParts>
        <batchChangeSet1>
          <batchChangeSetPart1>
            <method>POST</method>
            <uri>Businesspartner</uri>
            <headers>
              <header>
                <headerName>Accept</headerName>
                <headerValue>application/json;odata.metadata=minimal</headerValue>
              </header>
              <header>
                <headerName>Content-Type</headerName>
                <headerValue>application/json; odata.metadata=minimal; odata.streaming=true</headerValue>
              </header>
            </headers>
            <body>
              <Businesspartner>
                <Businesspartner>
                  <ID>2f6309ae-5b70-42b9-aabf-fc01850a1243</ID>
                  <NAME>Lars Vlyminckx</NAME>
                </Businesspartner>
                <Businesspartner>
                  <ID>2f6309ae-5b70-42b9-cabf-fc01850a1243</ID>
                  <NAME>John Doe</NAME>
                </Businesspartner>
              </Businesspartner>
            </body>
          </batchChangeSetPart1>
        </batchChangeSet1>
      </batchParts>

       

      Batch Output XML

      <batchPartsResponse>
        <batchChangeSetResponse>
          <batchChangeSetPartResponse>
            <headers>
              <header>
                <headerName>content-type</headerName>
                <headerValue>application/json;odata.metadata=minimal</headerValue>
              </header>
              <header>
                <headerName>location</headerName>
                <headerValue>Businesspartner(2f6309ae-5b70-42b9-aabf-fc01850a1243)</headerValue>
              </header>
              <header>
                <headerName>odata-version</headerName>
                <headerValue>4.0</headerValue>
              </header>
            </headers>
            <statusInfo>Created</statusInfo>
            <body>
              <Businesspartner>
                <Businesspartner>
                  <createdAt>2021-04-28T07:18:56.099Z</createdAt>
                  <modifiedBy>anonymous</modifiedBy>
                  <ID>2f6309ae-5b70-42b9-aabf-fc01850a1243</ID>
                  <createdBy>anonymous</createdBy>
                  <modifiedAt>2021-04-28T07:18:56.099Z</modifiedAt>
                  <NAME>John Doe</NAME>
                </Businesspartner>
              </Businesspartner>
            </body>
            <statusCode>201</statusCode>
          </batchChangeSetPartResponse>
        </batchChangeSetResponse>
      </batchPartsResponse>

      As you can see only the last 1 is created.

       

      Can you help me?

       

      Thanks in advance.

       

      Lars

      Author's profile photo Biplob Ghosh
      Biplob Ghosh
      Blog Post Author

      Hi Lars,

      You are trying to insert two entities in one batchchangesetpart. You should create a second batchchangesetpart for the second entity.

      Regards

      Biplob

      Author's profile photo Vinicius Souza
      Vinicius Souza

      Hello,

       

      Where should I use the Function Import's XML?

       

      It's not clear.

       

      Att.,

      Vinicius