BPM OData: Exploring the Service
What is the BPM OData Service?
The BPM OData Service is a built-in REST service exposing selected functionalities of the BPM Public API. The service implements the Open Data Protocol (OData) and thus provides a uniform way to easily access the exposed data and functionalities. With help of this service you can easily implement a custom UI with access to BPM related data and operations. This accelerates, for example, the implementation of a custom Task Execution UI with SAPUI5, since SAPUI5 can directly connect with the service to fetch data or perform actions. This is shown in the second post of this series. The goal of this blog post is to explain the technical basics of the BPM OData Service and to demonstrate how to explore this service.
From A to Z
- Access to the metadata of a BPM task
- Access to the input and output data of a BPM task
- Claim and complete a BPM task
Technical Basics
URL Part / Service Name | BPM Tasks OData Service | BPM Task Data OData Service |
---|---|---|
Technical Service Name | tasks.svc | taskdata.svc |
Use Case | Get metadata of a task, claim a task | Get task input and output data, complete a task |
Required Path Segment(s) | – | Task instance ID value |
Supported OData Resource Paths | $metadata, TaskCollection, Claim | $metadata, InputData, OutputData |
Supported OData Query Options | $format | $expand, $format |
Running Example
<complexType name="Customer">
<sequence>
<element name="firstName" type="string"></element>
<element name="lastName" type="string"></element>
<element name="address-street" type="string"></element>
<element name="address-city" type="string"></element>
<element name="address-zip" type="integer"></element>
<element name="address-country" type="string"></element>
<element name="currency" type="string" default="EUR"></element>
</sequence>
</complexType>
<complexType name="Credit">
<sequence>
<element name="creditLimit" type="double"></element>
</sequence>
</complexType>
Access to the Metadata of a BPM Task
Based on the technical basics described in the previous section, the following sections are now getting back to the steps needed to come from A to Z. This section starts with step A and describes how to access the metadata of a BPM task in order to inspect, for example, the priority of a task. The data referred here as metadata of a task corresponds to the TaskAbstract known from the BPM Public API.
In order to get the metadata of a task, the BPM Tasks OData Service is used along with the OData resource path TaskCollection. The Task instance ID is passed as URL parameter in parentheses and quotation marks. The OData $format query option is used to specify that the service response should be in JSON format.
The table below shows the URL used to access the metadata of a BPM task along with the service response:
HTTP Method | GET |
---|---|
URL | …/bpmodata/tasks.svc/TaskCollection(‘e898ab9c36f611e3a6bf0000006379d2‘)?$format=json |
Response Body (simplified) |
|
The response of the HTTP request above contains the requested data in a key-value pair format. OData supports the possibility to describe the underlying data model, the so-called Entity Data Model (EDM). This data model is exposed with a Service Metadata Document describing entities, their properties and relations among different entities. With help of this information you can for example find out, that the priority of a task is a property of type String and the property is optional (Nullable=true). This document can be requested with the $metadata query option.
The table below shows the URL used to get the metadata of the BPM Tasks OData Service and the corresponding response:
HTTP Method | GET |
---|---|
URL | …/bpmodata/tasks.svc/$metadata |
Response Body (simplified) |
|
Access to the Input and Output Data of a BPM Task
The input data of a task contains the data used to initialize the task while the output data contains the result of the completed task.
Input Data
Accessing the input data returns a data object called InputData which contains the data as specified with the input data mapping of the human activity within the process model. In the running example it is an entity called Customer containing the data set of a customer with the first name John and the last name Doe.
In order to get the Input Data of a Task, the BPM Task Data OData Service is used along with the OData resource path InputData. The Task instance ID is passed as URL path segment and as URL parameter. It is also possible not to pass the task instance ID as parameter, but this will change the format of the response. Instead of returning the Input Data as a single entity, an Atom feed is returned which contains the Input Data as single element.
The OData $expand query option is used to specify that referenced entities should be represented inline within the service response. The name of the entities to expand is passed with the option. In the example below the referenced entity Customer is getting expanded and therefore represented inline in the response. Omitting the expand option would result in a service response containing only the wrapper element InputData without any further data.
The table below shows the URL used to access the input data of a BPM task along with the service response:
HTTP Method | GET |
---|---|
URL | …/bpmodata/taskdata.svc/e898ab9c36f611e3a6bf0000006379d2/InputData(‘ e898ab9c36f611e3a6bf0000006379d2‘)?$expand=Customer&$format=json |
Response Body |
|
Like the BPM Tasks OData Service, the BPM Task Data OData Service also supports requesting the Service Metadata Document, but specific for each particular task instance ID. This document describes the structure of the input data as well as the structure of the output data. The returned EDM is generated automatically from the XSD defining the data types used by the BPM task and thus provides the information about name, type and default value of the single properties.
In the example below, the task Verify Customer Data is used. The input and output data of this task have the same data type, i.e. Customer. This is also reflected in the resulting EDM. In case of a different XSD structure for input and output data, EDM structure would differ as well.
The table below shows the URL used to get the metadata of the BPM Task Data OData Service and the corresponding response:
HTTP Method | GET |
---|---|
URL | …/bpmodata/taskdata.svc/e898ab9c36f611e3a6bf0000006379d2/$metadata |
Response Body (simplified) |
|
Output Data
The service request to get the task output data is almost the same as the one to get the input data except of the OData entity set name that is OutputData in this case. Requesting the output data of an open task will return an empty data object, since the output data of a task is only set when completing the task.
The table below shows the URL used to access the output data of a BPM task along with the service response:
HTTP Method | GET |
---|---|
URL | …/bpmodata/taskdata.svc/e898ab9c36f611e3a6bf0000006379d2/OutputData(‘ e898ab9c36f611e3a6bf0000006379d2‘)?$expand=Customer&$format=json |
Response Body |
|
Claim and Complete a BPM Task
In SAP NetWeaver BPM, you must claim a task before you will be able to complete it. This can be done with help of the BPM Tasks OData Service using the OData resource path Claim. The task instance ID of the respective task is passed with the query option InstanceID.
In contrast to the requests mentioned before (for example, getting the input data of a task), this activity is not about getting some data from the OData Service but about executing a particular action, i.e. claiming a task. Thus, an HTTP POST request is used to trigger the action instead of an HTTP GET request, which is usually used to request some data. A POST request includes some headers and a body containing some data. The headers are explained later along with a description of how you could actually execute a POST request.
The table below shows the URL used to claim a BPM task:
HTTP Method | POST | |
---|---|---|
URL | …/bpmodata/tasks.svc/Claim?InstanceID=’e898ab9c36f611e3a6bf0000006379d2′ | |
Request Headers | Authorization | Basic dXNlcm5hbWU6cGFzc3dvcmQ= |
X-CSRF-Token | 781057a9-b96a-468c-b393-981f98292335 | |
Request Body | <empty> | |
Response Body | OData entry representing the claimed BPM Task |
Once the task is claimed, you will be able to complete it. For that purpose, you send an HTTP POST request to the URL similar to the one that is used to get the task output data. The request body contains the output data that will be used to complete the task. In case of the running example, a modified version of the input data is used to complete the task. This is possible because the task uses the same data type for input and output data. If the data types for input and output data are different, the output data needs to be created based on the described structure in the EDM.
The table below shows the URL used to complete a BPM task along with the service response:
HTTP Method | POST | |
---|---|---|
URL | …/bpmodata/taskdata.svc/e898ab9c36f611e3a6bf0000006379d2/OutputData | |
Request Headers | Authorization | Basic dXNlcm5hbWU6cGFzc3dvcmQ= |
X-CSRF-Token | 781057a9-b96a-468c-b393-981f98292335 | |
Accept | application/json | |
Content-Type | application/json | |
Request Body |
|
|
Response Body |
|
Attentive readers probably noticed that the currency property has not been specified in the POST request body, but it is set to EUR in the service response. In case the value for a required property is not provided in the POST request body (currency is a required element having defined a default value in the XSD definition), the service will use its default value to complete the task.
How to Send a POST Request?
As it was mentioned before, HTTP POST requests are used to claim and complete a BPM task. For performing a POST request a regular web browser cannot be used. To perform a POST request you need to use a REST client. For this purpose, we will use Postman. It is a REST client distributed as an add-on for Google Chrome browser. In case you want to use your own REST client instead of Postman, please make sure that the client supports the reuse of the same HTTP session across different HTTP requests. Otherwise, you might face with problems during claiming or completing a BPM task.
The screenshot below shows how to send a POST request to complete a BPM task with Postman:
What Do all These HTTP Headers Mean?
As some of you probably noticed there are some HTTP headers specified for the POST requests to claim and complete the task. Content-Type and Accept are standard HTTP headers used to specify media type for the request and response bodey respectively. Authorization header is used to specify user credentials for authentication. In the example, this header has a Base64-encoded value generated by Postman. To generate this value in Postman go to the Basic Auth tab of the Postman UI, enter user credentials and click the Refresh headers button.
A POST request can be considered as a write operation. It means that additional security considerations should be taken into account to secure BPM process data. The BPM OData services are implemented to prevent CSRF attacks in case write operation is performed. This is implemented with the HTTP header X-CSRF-Token, which is used to send CSRF tokens in both directions. As it was mentioned before, this header is checked only for write operations, i.e. only for POST requests. The CSRF token is generated by the service, which means that before you specify the header value for a POST request you need to get it from the service. For that purpose, you can send any valid GET request to the service adding X-CSRF-Token HTTP header with the value Fetch. After receiving the generated value from the service, you can use this value in the HTTP header of your POST request to complete a task. The generated value is valid only within the same HTTP session.
The figure below shows the URL used to request the generation of the value for the X-CSRF-Token header along with the response containing the generated value:
Restrictions
Providing access to a task’s input and output data requires knowledge of the used data types. In BPM these data types are defined with an XML Schema Definition (XSD). This XSD is translated by the BPM OData Service in an OData conform representation of the data structure, i.e. EDM. As of SAP NetWeaver 7.3 EHP1 SP09, this translation only supports a complex type acting as a wrapper, which contains some primitive types. See also the running example, which uses a complex type Customer with primitive types describing the name and the city of the customer.
In case your wrapper element does not only contain primitive types but also complex types, you can bypass this restriction by unwinding the embedded complex types to own simple properties with the name of the complex data type as prefix. This workaround is shown below:
Complex type unwound to simple properties:
<complexType name="Customer">
<sequence>
<element name="firstName" type="string"></element>
<element name="lastName" type="string"></element>
<element name="address-street" type="string"></element>
<element name="address-city" type="string"></element>
<element name="address-zip" type="integer"></element>
<element name="address-country" type="string"></element>
<element name="currency" type="string" default="EUR"></element>
</sequence>
</complexType>
Use of embedded complex type:
<complexType name="Customer">
<sequence>
<element name="firstName" type="string"></element>
<element name="lastName" type="string"></element>
<element name="address" type="Address"></element>
<element name="currency" type="string" default="EUR"></element>
</sequence>
</complexType>
<complexType name="Address">
<sequence>
<element name="street" type="string"></element>
<element name="city" type="string"></element>
<element name="zip" type="integer"></element>
<element name="country" type="string"></element>
</sequence>
</complexType>
More information about the restrictions of the BPM OData Service as of SAP NetWeaver 7.3 EHP1 SP09 you can find in the BPM OData Services documentation.
Error Handling
Sometimes bad things happen. In case something goes wrong during the service request processing, you will get a service response containing a log ID along with a corresponding HTTP status code, e.g. HTTP 500 (Internal Server Error) or HTTP 404 (Not Found). You can inspect the log entry identified with the given log ID by using the SAP NetWeaver Log Viewer. The technical information about the error including the exception stack trace is located in SAP NetWeaver Developer Traces.
Conclusion
This part has shown the whole round-trip for a BPM task; the metadata and the input data of a task can be retrieved, a task can be claimed for a given user, and the output data can be sent to complete a task. In the next part we will show how this round-trip of operations can be used to implement a Task Execution UI based on SAPUI5.
Thanks a lot for this great blog about BPM OData service. After reading your well structured blog, I finally understood what the BPM OData service is about and how to use it 🙂
Now, I am curious about the next blog describing the service consumption with
a SAPUI5 application...
Nice Blog ... Thanks for sharing... 🙂
Great explanation of the BPM Odata service. Thanks a lot for providing all the details. Looking forward to read more from you....
Great Blog..thanks for sharing this useful information. Waiting for the next blog in this series.
Hi Vitaly, This is great background info. The follow on blog you mention ... is this http://scn.sap.com/community/bpm/blog/2013/10/31/bpm-odata-implementing-a-basic-custom-task-execution-ui or are you planning something else?
Every little bit that helps with mountaineering the learning curves is welcome!
Hi Jocelyn,
You are right, http://scn.sap.com/community/bpm/blog/2013/10/31/bpm-odata-implementing-a-basic-custom-task-execution-ui is the blog post that is mentioned here. I've added links to it.
And yes, we are planning something else. So, stay tuned 🙂
Great blog Vitaly..!
Great job, showing SAP how documentation should look like.
You saved us a lot of time and work.
There should be a link from BPM Inbox to this blog. 🙂
Hi Vitaly Yarmolik,
Amazing blog ,excellent explanation.
Just one small request cam you create a document this in SCN as a how to or step by step guide.
Cheers
Piyas
Hi Vitaly Yarmolik
Great blog! I can see that, in the example, basic authentication is used to invoke the OData endpoint. I need to invoke this service from a remote system, thus I'd like to authenticate through some form of SSO.
Can this be configured or we have to stick to basic authentication?
Thanks,
Vincenzo
I'll answer this by myself 🙂
Yes, using the NWA you can configure authentication as you wish, as you would do with any other java application/endpoint on the application server
Hi Vincenzo,
You are right.
From the technical point of view, the BPM OData Services are implemented and deployed as a java web application. As it was mentioned in the blog post, the application is hosted at 'bpmodata' context root. All the configuration capabilities, which are provided by SAP NetWeaver for java web applications, are also applicable for the BPM OData Services. SSO and general security configuration is not an exception.
More information about configuring SSO for web applications can be found in Single Sign-on for Web Applications section of the SAP NetWeaver AS Java documentation.
Best Regards,
Vitaly
Hi vitaly,
Thanks for such a nice blog.
I am getting error Http 501 for claim task service.
can you please help me in this.
below one is the screen captured for claim service.
Hi I experienced the same issue.
The problem is that Task instance ID must be between quotes ''
Like:
/bpmodata/tasks.svc/Claim?InstanceID='e698e6f8641511e4bded00000034b6ba'
Otherwise you get that strange error.
I'd advise Vitaly Yarmolik if he could kindly update the example!
Regards
Vincenzo
Thanks a lot Vincenzo.
its working.
-Trim
Hi Vincenzo,
Thank you for pointing it out.
I've updated the example accordingly.
Best Regards,
Vitaly
First of all thanks for the great article.
I am working this tutorial until the claim.
but i have problem of executing the OutputData post request. I get the error 500, Invalid data.
For the get output data i have to use the url below
/bpmodata/taskdata.svc/7febea50e98e11e4caea0000180c5a5e/OutputData('7febea50e98e11e4caea0000180c5a5e')?$expand=VerifyCustCompleteEventTypeOUTPUT/VerifyCustCompleteEvent/DO_CUstomer&$format=json
i have to use the expand
VerifyCustCompleteEventTypeOUTPUT/VerifyCustCompleteEvent/DO_CUstomer
to get the DO_CUstomer.
In this case do i have to use the body for post OutputData like in the screenshot.
Any suggestins are welcome. Thanks in advance. Regards, Antony.
Hi Antony,
You are getting 500 / INVALID_DATA service response, because your POST request body is not correct.
According to the information from the blog post, "In case of the running example, a modified version of the input data is used to complete the task. This is possible because the task uses the same data type for input and output data. If the data types for input and output data are different, the output data needs to be created based on the described structure in the EDM."
In your case, EDM metadata (response for $metadata request) for the task output data should look like this
<EntityType Name="OutputData">
...
<NavigationProperty Name="VerifyCustCompleteEventTypeOUTPUT" ...
</EntityType>
When you send POST request for OutputData entity set, the request body should represent an entity for OutputData entity type, i.e. it must have data for VerifyCustCompleteEventTypeOUTPUT navigation property and the nested properties of this navigation property. As a result, "VerifyCustCompleteEventTypeOUTPUT" should be the parent JSON object in the request body.
The correct POST request body for your type of the task output data is below:
{
"VerifyCustCompleteEventTypeOUTPUT" : {
"VerifyCustCompleteEvent" : {
"DO_CUstomer" : {
"firstName": "Max",
"lastName": "Mustermann",
"street": "Haupt Str.",
"city": "Walldorf",
"zip": "69190",
"country": "Germany"
}
}
}
}
More information about the reasons for the error codes in the service responses as well as for the possible solutions can be found in the Troubleshooting Guide.
Best Regards,
Vitaly
Hi Vitaly,
Thanks for the quick reply.
I tried that in the first place. It was not working.
Still i get the same error.
I will check the link that you mention.
Regards,
Antony.
Hi Vitaly,
I am still searching the solution for this error.
I went to the developer trace and get this message below.
[EXCEPTION] com.sap.bpm.odata.exception.BPMODataException: Illegal argument for method call with message 'DO_CUustomer'.
i went to the blog about the input output data problem.
I got the result from http://..bpmodata/taskdata.svc/2ef6db6aea7411e491460000180c5a5e/OutputData?$expand=VerifyCustCompleteEventTypeOUTPUT/VerifyCustCompleteEvent/DO_CUstomer&$format=json
My body data is below as you mentioned.
{
"VerifyCustCompleteEventTypeOUTPUT" :
{
"VerifyCustCompleteEvent" :{
"DO_CUustomer":
{ "city": "Aaigem", "country": "Bel", "currency":"eur", "firstName":"Antony", "lastName":"Ferminus", "street":"Opaaigem", "zip":"9420"
}
}
} }
I have no idea why this error comes again. All my DO_CUstomer fields are string fields.
If you have any suggestions please let me know.
Thanks in advance.
regards,
Antony.
Hi Antony,
Please add me as a connection on SCN. You should click 'Follow' button on my profile page. After that we will be able to use private messaging in order not to publish private data (e.g. XSD file of your output data, etc.) as a comment for the blog post.
Best Regards,
Vitaly
Hi Vitaly,
Good news. It is working. As you said, i created a new small process name age with small xsd like below.
Used the body parameter like below
{ "Output_nameageCompleteEventTypeOUTPUT":{ "Output_nameageCompleteEvent" : { "DO_User":{ "name" : "Antony", "age": "35" } } } }
I got the result 201 created and the task is completed. Thanks for you effort to helping me out. Really appreciated.
Regards,
Antony.
Hi Antony,
That's great! You are welcome 🙂
Coming back to your initial scenario, I'm almost sure that the problem was in the modeled process, i.e. something was wrong either in the Input / Output mappings of the human activity or with the Data Objects configuration in the process context.
Best Regards,
Vitaly
Hi Vitaly,
Indeed. Now i have a clear idea of where things can go wrong.
I will recreate the process and test it again.
I am sure it will work.
I am now testing the start process for name age too.
Once again thaks a lot. You made my day.
Regards,
Antony.
Hello
I am not sure what is wrong but my processes.svc shows only two entities i.e ActiveProcessDefinition & ProcessInstance.
I cannot see ProcessCollection , CancelProcess , ResumeProcess and SuspendProcess.
https://answers.sap.com/questions/569295/bpm-odata-service-not-showing-up-all-entitysets.html
I have posted my question here , but no reply.
Regards
Fariha