Integration of SAP OnDemand Products with Business Suite via REST/OData Services
In my article “SAP Business Suite BO List” Solution Template, I described the integration with an SAP OnDemand solution (ByDesign, Customer OD) with SAP Business Suite via SOAP-based enterprise services using the ByDesign studio / Cloud Developer studio. In this article, I will show how to implement the same use case using REST / OData / SAP Gateway communication.
Background
In a SAP Business Suite system, you can expose REST/OData services via SAP Gateway. The article SAP Gateway Demo System provides a jump start into the world of SAP NetWeaver Gateway services. So, if you want to learn more about SAP NetWeaver Gateway and OData service, have a look at this article and the references in this article. In the section “Sales Order Example” you find a Sales Orders Query service, which I extended for the purpose of this article:
http://gw.esworkplace.sap.com/sap/opu/odata/sap/SALESORDERS/SOHeaders?&$filter=CustomerId eq ‘0000001390’&$top=2
The response contains the sales orders for the customer with customer number ‘0000001390’, the list is restricted to 2 entries ($top=2). The XML file looks like (excerpt):
<?xml version="1.0" encoding="utf-8" ?>
<feed xml:base="http://GW.ESWORKPLACE.SAP.COM:80/sap/opu/odata/sap/SALESORDERS/" xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<entry>
<id>http://GW.ESWORKPLACE.SAP.COM:80/sap/opu/odata/sap/SALESORDERS/SOHeaders('0000008078')</id>
<m:properties>
<d:OrderId>0000008078</d:OrderId>
<d:DocumentType>TA</d:DocumentType>
<d:DocumentDate>2002-10-17T00:00:00</d:DocumentDate>
<d:CustomerId>0000001390</d:CustomerId>
<d:OrderValue>35000.00</d:OrderValue>
<d:Currency>EUR</d:Currency>
</m:properties>
</content>
</entry>
</feed>
We want to consume this service in our SAP OnDemand solution.
Solution
Let us revisit the solution described in the article “SAP Business Suite BO List” Solution Template . This solution contains an embedded component BusinessObjectList.EC.uicomponent (EC). This EC invokes a custom BO BusinessObjectList and triggers the GetResult action of the BO. The GetResult action calls a web service that reads a list of SAP business suite BOs. The list is displayed in the EC. In the mentioned solution, the service call is a SOAP-based service call. In the solution described here, we will work with the same UI and business object and just replace the implementation of the SOAP-based web service call in the GetResults action with a REST-based service call.
Before we start the implementation, we have to configure the REST web service in the ByDesign or Customer OD system.
- To do so, create a new Mashup Web Service of type REST. You can do this from the studio (Add New Item dialog) or from the Application and User Management. You user must be enabled as key user in the studio. See the screenshot below.
- Set the authentication method to “basic” and enter name and password (This will be done by the key user in the production system.)
- Enter the URL mentioned above and click “Extract Parameters”. The system shortens the URL and extracts the parameters “$filter” and “$top”.
- Delete the values in column “Constant”. See the result in the following figure.
- Save the service configuration.
Figure: Mashup Web Service Configuration
As a second step, we do the implementation of the GetResults action. The first part of the implementation is:
var parameter : NameAndValue;
var parameters : collectionof NameAndValue;
var response;
var xml;
parameter.Name = "$filter";
parameter.Value = "CustomerId eq '0000001390'";
parameters.Add(parameter);
parameter.Name = "$top";
parameter.Value = "10";
parameters.Add(parameter);
response = WebServiceUtilities.ExecuteWebService("PW00008", parameters);
// for test purpose only – remove later
raise WebServiceContentError.Create("I", "Returncode: " + response.ReturnCode);
xml = response.ResponseContent;
The first part of the code fills the parameters; in our example the customer ID is hard-coded. The following line executes the web service. The ID of the web service “PW00008” is the ID that you can see in of the web service configuration screenshot. The final line fills the response content into the xml variable.
In case of the SOAP-based web services, you can generate a proxy from the WSDL file that does the parsing of the web service message. For REST-based web services, there is no proxy generation available; so the parsing of the message must happen in the code. The following code snippet shows the parsing for some selected elements:
var s1;
var l1;
var f1;
var pos = 0;
var pos1 = 0;
var i = 0;
var newDocData : elementsof BusinessObjectList.List;
while (i < 100) {
pos = xml.Find("<entry>", pos1);
if (pos < 0) { break; }
pos1 = pos + 7;
f1 = "<d:OrderId>"; l1 = 10;
pos = xml.Find(f1, pos1);
if (pos > 0) { s1 = xml.Substring(pos + f1.Length(), l1); }
newDocData.ID.content = s1;
f1 = "<d:CustomerId>"; l1 = 10;
pos = xml.Find(f1, pos1);
if (pos > 0) { s1 = xml.Substring(pos + f1.Length(), l1); }
newDocData.Name = s1;
this.List.Create(newDocData);
i = i + 1;
}
Great Blog Thomas, thanks for sharing this information!
Thanks Thomas,
It will really a helpful ..:)
Hi Thomas,
I am working on integrate other system with COD using REST API provided by them, the response is in JSON format,
The problem is parsing the JSON response.
Is there no other way to parse the response, because in this way we must know the length of string which I want to save as a value. In my case I will get huge response, below is some part of the response
"fields": {
"project": {
"id": "10600"
},
"summary": "something's wrong",
"issuetype": {
"id": "6"
},
"assignee": {
"name": "sunil"
},
"reporter": {
"name": "kumar"
},
"priority": {
"id" : "8"
},
"security": {
"id": "10000"
},
"versions": [
{
"id": "10000"
}
],
Here I can't guess the length of "name":"sunil" it could be "name":"Thomas". Here sunil contain 5 character and Thomas contain 6 character, how can we know the length from the response?
Kindly confirm that if there is a better way to parse the response, the way we have in other programming language and also confirm how to generate parameter from JSON format given into the body( http://scn.sap.com/thread/3406128 )
Thanks
Sunil
Sunil... I totally agree with you on this and it is the main reason I have not attempted this type of integration... (or have written a middle tier to translate the Rest service into a standard webservice that Bydesign can actually use)
Hi Sunil,
in my latest post, I provide some coding that parses a JSON into a hierarchical table: How to Parse a String in JSON Format in ABSL.
Best regards,
Thomas
.
Hello Thomas,
We have similar request to send data from C4C to external tool,
below is the structure what is required to be populated from PDI.
Could you please help with some pointers
------------------------------------------------------------
{
"version":{
"versionId":"1.0.0",
"plattform":{
"id":"IOS/ANDROID/WEB/WINDOWS",
"application":"ApplicationID"
}
},
"timeSpan":{
"spanStart":1442918257658,
"spanEnd":1442918258658
},
"deviceInformation":{
"deviceId":"4b95ecd26af00a989f215ad77a47993f4ca61521",
"screenSize":1,
"modelName":"iPhone 5 / User Agent",
"countryCode":"de"
}
}
------------------------------------------------------------
Best Regards,
Sumukh Kapoor.
Thanks for the post..
Hi Thomas,
I hope you are well, I have the following question:
I'm doing a calling REST/ODATA and are working properly. But only with a filter, when I place more than one wotks with the first, i explain in detail:
When i place the filter "CIM_SUB_TYPE" Works correctly:
https://myxxxx.sapbydesign.com/sap/byd/odata/fin_generalledger_analytics.svc/RPZ0519BBAC3EED0217F1C61CQueryResults?$select=CCOMP_UUID,CIM_BP_UUID,TIM_BP_UUID,CSP_CDT_F_DATE,KCOVERDUE_DAYS,KCOVERD_AMNT,FCOVERD_AMNT&$filter CIM_SUB_TYPE_C eq '1'
When i place the filter "CCOMP_UUID" Works correctly:
https://myxxxx.sapbydesign.com/sap/byd/odata/fin_generalledger_analytics.svc/RPZ0519BBAC3EED0217F1C61CQueryResults?$select=CCOMP_UUID,CIM_BP_UUID,TIM_BP_UUID,CSP_CDT_F_DATE,KCOVERDUE_DAYS,KCOVERD_AMNT,FCOVERD_AMNT&$filter CCOMP_UUID eq '1000'
But when I put both filters "CIM_SUB_TYPE" and "CCOMP_UUID" only Works the first filter.
https://myxxxx.sapbydesign.com/sap/byd/odata/fin_generalledger_analytics.svc/RPZ0519BBAC3EED0217F1C61CQueryResults?$select=CCOMP_UUID,CIM_BP_UUID,TIM_BP_UUID,CSP_CDT_F_DATE,KCOVERDUE_DAYS,KCOVERD_AMNT,FCOVERD_AMNT&$filter CCOMP_UUID eq '1000'&& CIM_SUB_TYPE_C eq '1'
So, how do the filters is correct? The "filter" command Works only for a filter?
regards,
Joe Gonzales.
Excellent blog Thomas Schneider
Thank you for sharing this nice piece of info.
The XML parser helped me a lot for my own parser.
Best regards.
Jacques-Antoine Ollier