Batch Request in Netweaver Gateway(Multiple Operations into a Single Request)
This blog contains information regarding batch concept in SAP NetWeaver Gateway Consumers . The OData Batch requests allow the grouping of multiple operations into a single HTTP request payload. I have seen lot of discussion regarding the batch concept.
This is a brief blog to explain how to implement batch in SAP system and how to make batch gateway service calls for READ,CREATE and UPDATE.
In SAP we don’t have to write any additional logic to implement batch, just have to redefine/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN and/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END methods as shown below.
READ :
Example of executing a batch request containing multiple Read operations.
URL:
http://**************/sap/opu/odata/sap/<Main_Service_Name>/$batch
HEADER:
Authorization: SAP ID & PASSWORD
x-csrf-token: Enter Token
Content-Type: multipart/mixed; boundary=batch
BODY:
–batch
Content-Type: application/http
Content-Transfer-Encoding: binary
Accept: application/xml
GET ABCCollection/?$filter= EMP_ID eq ‘10000030’ HTTP/1.1
–batch
Content-Type: application/http
Content-Transfer-Encoding: binary
Accept: application/jsonxml
GET ABCCollection/?$filter=EMP_ID eq ‘10000031’ HTTP/1.1
–batch–
CREATE:
Example of executing a batch request containing multiple Create operations.
URL:
http://**************/sap/opu/odata/sap/<Main_Service_Name>/$batch
HEADER :
Authorization: SAP ID & PASSWORD
x-csrf-token: Enter Token
Content-Type: multipart/mixed; boundary=batch
BODY:
–batch
Content-Type: multipart/mixed; boundary=changeset
–changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
POST ABCCollection HTTP/1.1
Content-Type: application/atom+xml
Content-Length: 588
<?xml version=”1.0″ encoding=”utf-8″ standalone=”yes”?>
<atom:entry xmlns:atom=”http://www.w3.org/2005/Atom“
xmlns:d=”http://schemas.microsoft.com/ado/2007/08/dataservices“
xmlns:m=”http://schemas.microsoft.com/ado/2007/08/dataservices/metadata“>
<atom:content type=”application/xml”>
<m:properties>
<d:EMP_ID>10000033</d:EMP_ID>
<d:FIRST_NAME>MIKE</d:FIRST_NAME>
<d:LAST_NAME>JOHNSON</d:LAST_NAME>
</m:properties>
</atom:content>
</atom:entry>
–changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
POST ABCCollection HTTP/1.1
Content-Type: application/atom+xml
Content-Length: 588
<?xml version=”1.0″ encoding=”utf-8″ standalone=”yes”?>
<atom:entry xmlns:atom=”http://www.w3.org/2005/Atom“
xmlns:d=”http://schemas.microsoft.com/ado/2007/08/dataservices“
xmlns:m=”http://schemas.microsoft.com/ado/2007/08/dataservices/metadata“>
<atom:content type=”application/xml”>
<m:properties>
<d:EMP_ID>10000034</d:EMP_ID>
<d:FIRST_NAME>ALLAN</d:FIRST_NAME>
<d:LAST_NAME>XAVIER</d:LAST_NAME>
</m:properties>
</atom:content>
</atom:entry>
–changeset–
–batch–
UPDATE:
Example of executing a batch request containing multiple Update operations(Change names).
URL:
http://**************/sap/opu/odata/sap/<Main_Service_Name>/$batch
HEADER :
Authorization: SAP ID & PASSWORD
x-csrf-token: Enter Token
Content-Type: multipart/mixed; boundary=batch
BODY:
–batch
Content-Type: multipart/mixed; boundary=changeset
–changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
PUT ABCCollection(‘10000033’) HTTP/1.1
Content-Type: application/atom+xml
Content-Length: 588
<?xml version=”1.0″ encoding=”utf-8″ standalone=”yes”?>
<atom:entry xmlns:atom=”http://www.w3.org/2005/Atom“
xmlns:d=”http://schemas.microsoft.com/ado/2007/08/dataservices“
xmlns:m=”http://schemas.microsoft.com/ado/2007/08/dataservices/metadata“>
<atom:content type=”application/xml”>
<m:properties>
<d:EMP_ID>10000033</d:EMP_ID>
<d:FIRST_NAME>MIKE_CHANGE</d:FIRST_NAME>
<d:LAST_NAME>JOHNSON_CHANGE</d:LAST_NAME>
</m:properties>
</atom:content>
</atom:entry>
–changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
PUT ABCCollection(‘10000034’) HTTP/1.1
Content-Type: application/atom+xml
Content-Length: 588
<?xml version=”1.0″ encoding=”utf-8″ standalone=”yes”?>
<atom:entry xmlns:atom=”http://www.w3.org/2005/Atom“
xmlns:d=”http://schemas.microsoft.com/ado/2007/08/dataservices“
xmlns:m=”http://schemas.microsoft.com/ado/2007/08/dataservices/metadata“>
<atom:content type=”application/xml”>
<m:properties>
<d:EMP_ID>10000034</d:EMP_ID>
<d:FIRST_NAME>ALLAN_CHANGE</d:FIRST_NAME>
<d:LAST_NAME>XAVIER_CHANGE</d:LAST_NAME>
</m:properties>
</atom:content>
</atom:entry>
–changeset–
–batch–
Reference Links:
http://help.sap.com/saphelp_gateway20sp06/helpdata/en/90/dc8363306c47d3b2fca1398f5de94b/content.htm
Nice Blog, thank you. It will be very helpful.
Thanks Pinaki........ 🙂
Thanks Chembra
Nice Blog..
Thanks Suman........ 🙂
For batch read I have put the following content on the BODY part
--batch
Content-Type: application/http
Content-Transfer-Encoding: binary
GET ABCCollection(ID='123',DESC='ABC') HTTP/1.1
--batch--
You are passing filter parameters, I guess its batch query.
Regards,
Pinaki
Thanks pinaki instead of Read i put Query in my document...
Hi Arun Chembra,
Nice document, Thanks for sharing...
Regards,
Ramesh.T
Thanks Ramesh
Good one Arun.
Hi Arun,
Your Blog Helped me alot.
I can Succesfully send the Data To backend from REST Client.
Presently I am Doing Update Operation For Sales Order i.e change of quantity ,rejection ...
my problem is we cannot send the data from Mobile Device the data to backend.
please suggest me a way how to pass the Request Body from Mobile Side.
Regards,
Raju.
Arun, nice blog.
Do you happen to have any advanced examples, like an implementation (use case) of the /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN method in combination with its sibling /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END?
I see some hints in the docs what one can do with these, but not any actual example.
Cheers, Wout
Hi Wout,
Thanks for your feedback...
Even i was not sure about the real time scenarios where we can implement the /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN method in combination with its sibling /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END .
While using batch you will not be able to use BAPI_TRANSACTION_COMMIT in this case you can implement the /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN and /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END to resolve this issue.
Thanks,
Arun
Hi Arun, yeah, indeed I haven't found any, except a ref in the help about preparing internal tables in BEGIN, then I assume filling internal tables in the individual CUD operations, and then committing the internal tables to the db in the END method.
I'm not sure however, how to pass along those internal tables. I can only come up with via MEMORY, but usually I regard that as a bad choice. Plus the individual CUD operations then need to be aware whether they are called within a CHANGESET or not.
Cheers, Wout
Hi Wout,
Yes, we have to achieve this via memory only, even though it was a bad choice 😎 .
Thanks,
Arun
Sorry Arun, I'm overcomplicating things with the MEMORY stuff. As all CHANGESET logic and CUD operations happen inside 1 instance of the Data Provider Class, you can just define attributes ("internal tables") to store the data and get that data in the CHANGESET_END method.
Hi Wout,
How did you accomplish to do this with the member table in the data provider class? Even when in the same changeset I noticed the runtime is reinstantiated for each change. So in my case I set the member variable "is_batch_request" in /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN. When I check for the variable in my entity's ENTITYSET_UPDATE_ENTITY, the variable is only initialized for the first entry of the batch request (within the same change set)..
When looking at the above code (see screenshot), it seems not possible to work with a member table? (Create + clear runtime) Or am I missing something?
Thanks in advance!
Hi Bjorn,
probably you already found out, I think you can use static member variables in the data provider class. These seem to be shared among the changes of a change set. This worked in a small test I did.
Best regards,
Matthias
Hi Matthias,
Using a static member variable did the trick, thanks a lot!
Kr,
Bjorn
Bjorn, sorry for the very late reply. I did use instance attributes, and this still works, as I'm just revisiting the code. (This is an embedded Gateway deployment.)
Not sure why the runtime is not reinstated in my case...
Cheers, Wout
For what i can understand, if I prepare a service with the Batch option and send multiple create operations, it will treat each one as individual and not by a whole right?
I have a table that needs to be analysed completely in a Create Operation but I'm not sure if the batch methods will work.
Hi Joel,
By using the batch request all changes you add to that batch changeset will be processed via one http request, saving you the separate round trips to the server.
For each create operation you added to the batch request however, the entityset_create_entity method will be called, acting on that single entry. I think my problem was similar to yours, and used a flag to have different behaviors in the create_entity method for normal and batch requests. In case of batch request, you can set a flag in the CHANGESET_BEGIN method of the DPC. When the batch flag is active, I do not update the entity in the database in the create_entity method, but instead append it to a member table of the DPC. After the last entry of the batch request, the CHANGESET_END method will be called, where you will have access to the entire table and can decide whether or not to write it to the database. Note that for this to work, both the flag and the table need to be static member attributes of the data provider class.
Hope this clears things up for you!
Kind regars,
Bjorn
In addition to Bjorn's answer. 1 Batch can contain multiple Changesets. A Changeset behaves transactionally. Please checkout the documentation on help.sap.com; it's pretty clear.
nice Blog..... Was very informatic and helpful.. =)
Regards,
Pavan Golesar
Sorry but it doesn't feel like adding EXIT in the changeset_end and changeset_begin will solve sending multiple entries for one entityset problem.
I have to admit, that your statement is right. I can't get my batch UPDATE to work.
Hello! Interesting blog, but how would creating these batch requests look like from the front-end using javascript/json?
Hi Arun ..! Thanks for the post.It helped me a lot.I have small doubt regarding header part.
what value should we pass to this x-csrf-token in header section..
Hi Arun,
I am getting status code 202 during my POST create operation , but not getting any other info in response area …even I put a external break point at create_entity …but still execution was not stopped there ..
Appreciate your help ..I paste below request
-batch
Content-Type: multipart/mixed; boundary=changeset
–changeset
Content-Type: application/http
Content-Transfer-Encoding: binary
POST SorditemSet HTTP/1.1
Content-Type: application/atom+xml
Content-Length: 588
<?xml version=”1.0″ encoding=”utf-8″ standalone=”yes”?>
<atom:entry xmlns:atom=”http://www.w3.org/2005/Atom“
xmlns:d=”http://schemas.microsoft.com/ado/2007/08/dataservices“
xmlns:m=”http://schemas.microsoft.com/ado/2007/08/dataservices/metadata“>
<atom:content type=”application/xml”>
<m:properties>
<d:Erdat>20161115</d:Erdat>
<d:Netwr> 94.35</d:Netwr>
<d:Waerk>GBP</d:Waerk>
<d:Kunnr>0000001066</d:Kunnr>
<d:Posnr>000010</d:Posnr>
<d:Matnr>90251178</d:Matnr>
<d:Kwmeng> 1.000</d:Kwmeng>
<d:Status>UNAU</d:Status>
<d:Vbeln>40000336</d:Vbeln>
</m:properties>
</atom:content>
</atom:entry>
–changeset–
–batch–-
Appreciate your help …if I am missing anything ..
Kind Regards
Sthiru
Where exactly we have to write business logic? Example reading and saving payload data into tables.
Hi, hello, I am having a problem now, when I call the request to create a purchase order, an error occurs as follows: <?xml version="1.0" encoding="utf-8"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code>005056A509B11EE3AEB5819C07C69E2F</code>
<message xml:lang="en">The server is refusing to process the request because the entity has an unsupported format</message>
<innererror xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<transactionid>457B9545FD6B0210E005BD3B9E76C48A</transactionid>
<timestamp>20181106012253.0217930</timestamp>
<Error_Resolution>
<SAP_Transaction>For backend administrators: run transaction /IWFND/ERROR_LOG on SAP Gateway hub system and search for entries with the timestamp above for more details</SAP_Transaction>
<SAP_Note>See SAP Note 1797736 for error analysis (https://service.sap.com/sap/support/notes/1797736)</SAP_Note>
</Error_Resolution>
</innererror>
</error>
My request address is: https://my300052-api.saps4hanacloud.cn/sap/opu/odata/sap/API_PURCHASEORDER_PROCESS_SRV/$batch
The parameters are: {
"PurchaseOrder": "4500000122",
"CompanyCode": "A010",
"PurchaseOrderType": "NB",
"Supplier": "1000000040",
"PurchasingOrganization": "A010",
"PurchasingGroup": "001",
"to_PurchaseOrderItem": {
"results": [
{
"PurchaseOrder": "4500000122",
"PurchaseOrderItem": "10",
"Plant": "A010",
"OrderQuantity": "10",
"PurchaseOrderQuantityUnit": "KG",
"PurchaseOrderItemCategory": "0",
"Material": "T62-15160000-0",
"to_AccountAssignment": {
"results": [
{
"PurchaseOrder": "4500000122",
"PurchaseOrderItem": "10",
"AccountAssignmentNumber": "1"
}
]
},
"to_PurchaseOrderPricingElement": {
"results": [
{
"PurchaseOrder": "4500000122",
"PurchaseOrderItem": "10",
"PricingDocument": "1000000229",
"PricingDocumentItem": "10",
"PricingProcedureStep": "60",
"PricingProcedureCounter": "1",
"FactorForConditionBasisValue": 3.14
}
]
},
"to_ScheduleLine": {
"results": [
{
"PurchasingDocument": "7000000000",
"PurchasingDocumentItem": "10",
"ScheduleLine": "1"
}
]
}
}
]
}
}