Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
maheshpalavalli
Active Contributor
Recently I was working a project that requires me to consume SAP Build Process Automation API in my app. So when I was looking at our SAP API hub, I found that the APIs for SAP Build are documented quite nicely - the next part is to consume the API. But in the world of JavaScript & cloud, there are many ways to consume an API. One of the popular approach is using Axios, but you might end of doing a lot of manual stuff to connect to the API, especially when you want to use Principal Propagation & connecting to CF.

That's when I discovered the SAP Cloud SDK, which helps to solve this by providing typed APIs for an Open API or OData service. It also offers multiple ways to connect to the APIs in your SAP BTP subaccount, using Service Binding, Destination and different authentication mechanisms, including OAuth User Token Exchange (Principal Propagation).

In this blog post, I will show how you can connect to the SAP Build Process Automation API using Client Credentials & Principal Propogation. For this, I will create a simple CAP application based on TypeScript using VSCode. You can do the same in a Node JS app or consume other SAP BTP APIs.


Extension app connecting to SAP Build Process Automation using SAP Cloud SDK (User Token Exchange)



Client Credentials Flow


Github

Scenario: [Consuming SAP Build Process Automation: Processes & Workflows] To fetch all the Tasks created for a workflow in the ready state.

Steps:

Assuming a new CAP app was already created using the template, Import the API in JSON format in the resources main folder as shown in this Github repo.

Initializing the project:

Ensure that ts-node is installed globally:
npm i -g typescript ts-node 

 

As this is Open API format, first install the Open API generator using the below command:
npm install @sap-cloud-sdk/openapi-generator

 

Now generate the typed client using the below command:
npx openapi-generator --input resources --outputDir srv/generated --skipValidation

 

[Optional] I also want to generate the cds file for this API, so I can use it as a returning type for my function import.
cds import './resources/SPA_Workflow_Runtime New.json'  --from openapi --as cds

 

add a service.cds file in srv folder and add the below code:
// Below code is from CDS Import from earlier step
using { Processes._.Workflows_types.TaskInstance as TaskInsance } from './external/SPA_Workflow_Runtime New.cds';

// New service to expose a function import
service sapCloudSDKBuildTS {
function getTaskInstances() returns array of TaskInsance;
}

Two things I did in the above code:

  1. We are loading the types of "TaskInstance" .

  2. We created our service and added a function import, which returns the task instances of type "TaskInstance".


Consuming the API using SAP Cloud SDK:

There are many ways to consume an SAP BTP API using SAP Cloud SDK. In this example, I will use Service Binding based approach, which only needs service instance created for SAP Build Process Automation service. To test locally, bind the service instance to the app using the below command:
cds bind process-automation --to spateamsint-spa:spateamsint-spa-key --kind process-automation

Here spateamsint-spa is the service instance name and spateamsint-spa-key is the key name.

In the code, first we have to import the TaskInstances API using the below code:
import { UserTaskInstancesApi } from "./generated/SPA_Workflow_Runtime New";

Add a service.ts file in srv folder to write the code return the Task Instances, when the function: getTaskInstances() is called. Check the code to do some copy-pasta (will explain in the coming steps).

As it's a typed client, you can explore all the available methods but we use getV1TaskInstances to fetch all the available Task Instances.
 const responseData = await UserTaskInstancesApi.getV1TaskInstances({
definitionId:
"form_simpleapprovalp_1@****.testworkflow.simpleapproval",
status: "READY",
}).execute({
destinationName: "process-automation",
serviceBindingTransformFn,
});

You can also observe that I've passed additional parameters like Status, which are part of the typings.

In the destinationName, you need to pass the service name, which in our case is process-automation.
Note: This is the service name, not the service instance name. SAP Cloud SDK will fetch the service instances associated with the service process-automation from VCAP_SERVICES that are loaded locally when we bound our application using CDS BIND for our local testing. You can also do this using an actual SAP BTP Destination, which I will show in the other example after this.

There is also another function that is passed - serviceBindingTransformFn. This is because only few services are by default supported by the SAP Cloud SDK to fetch the URL, Credentials etc., from the service instance automatically, and process-automation service is not one of them 😉

For this reason, we are passing this function, which has the below code:


As you can see I am using executeHttpRequest, part of SAP Cloud SDK to fetch the token. But you can also use Axios to make that code a bit shorter 😉 You can also find the Axios example commented in the github repo.

At the end, you will form an object with the required details and return it, which will be consumed by the SAP Cloud SDK and return our requested data. Run the app using the below command:
cds-ts watch --profile hybrid

Once you call the URL, it will return you all the tasks for the specified workflow.

eg: http://localhost:4004/sap-cloud-sdkbuild-ts/getTaskInstances()
Note: I am only covering the local installation & testing. You need to have mta.yaml with the neccessary resources & modules for it to run in SAP BTP CF environment and also need to adjust the package.json to update the start task. Check the CAP help for TypeScript for more information.

Principal Propagation (User Token Exchange)


Github

Scenario: [Consuming SAP Build Process Automation: Inbox] To fetch all the Workflow Tasks assigned to the logged in user. [Testing done Locally]

Steps:

Assuming a new CAP app was already created using the template, Import the API in EDMX format in the resources main folder as shown in this Github repo.

Initializing the project:

Ensure that ts-node is installed globally:
npm i -g typescript ts-node 

 

As this is an OData API, install the regular generator using the below command:
npm install @sap-cloud-sdk/generator

 

[Optional] Add a serviceMapping.json file with the below content, so you can skip adding the path while executing the requests:
{
"SPA_Workflow_Inbox": {
"directoryName": "com-sap-bpm-wfs-tcm-metadata-service",
"servicePath": "/public/workflow/odata/v1/tcm",
"npmPackageName": "com-sap-bpm-wfs-tcm-metadata-service"
}
}

 

Now generate the typed client using the below command. In case if you get any error related to "triple-beam" typings, install it. npm install --save @types/triple-beam
npx generate-odata-client --inputDir resources --outputDir srv/generated --overwrite -s "resources/serviceMapping.json"

 

add a service.cds file in srv folder and add the below code. It's self-explanatory, and you will have an idea from the previous example.
service sapCloudSDKBuildTS @(requires: 'authenticated-user') {
// define type {};
type TaskCollection {
instanceId: String;
status:String;
}
function getTaskInstances() returns array of TaskCollection;
}

 

Consuming the OData API using SAP Cloud SDK:

In this scenario, I will show how to consume the same using the Destination created in SAP BTP. So you need to bind the destination instance to test it locally.
cds bind destination --to destination-srv-instance:destination-srv-instance-key --kind destination

SAP Cloud SDK also requires XSUAA instance for fetching the destination. So bind it as below: (You can do this in the later steps, in XSUAA hybrid testing)
cds bind xsuaa --to xsuaa-srvins:xsuaa-srvins-key --kind xsuaa

 

Add a service.ts file in srv folder to write the code return the Task Instances for the logged-in user, when the function: getTaskInstances() is called. Check the code to do some copy-pasta.
const { taskApi } = wfApi();
const jwt = retrieveJwt((Request as any).req);
const result = await taskApi
.requestBuilder()
.getAll()
.top(5)
.execute({ destinationName: "sap_process_automation_service_user_token", jwt:jwt });

Code is pretty straightforward and it's typed, so it will be easy to figure out all the available methods. The only unique thing here is to fetch the jwt token, which again is provided by SAP Cloud SDK. This will be available once the user is authenticated.

In the destinationName, you must pass the destination that you created in your subaccount. eg:


But how to authenticate the user for local testing? - We will use an approuter to authenticate the user and forward the token to the service call. SAP CAP Documentation for XSUAA hybrid testing - which has explained this clearly

Follow the above documentation and add any missing node libraries (passport & xssec). Run the app router and run the application with the script in the main package.json.

With this, you will be able to fetch all the Workflow tasks assigned to you, and SAP Cloud SDK will perform the user token exchange for us. I am not showing how you can deploy this, as it's fairly easier with many the blog posts & tutorials talking about deploying a CAP app to SAP BTP CF environment.

In case if you want to do it manually using Postman, download the collection from this github repo and import it in your postman. Then fill up the collection variables, fetch the XSUAA token, perform user token exchange and use the token to fetch the assigned Tasks (TaskCollection).

 

Thant's it folks, Let me know your thoughts & if you know any better or alternative approach in doing this, please share here 🙂

Cheers!
Mahesh
7 Comments
rajasekhara0195
Discoverer
Hi Mahesh,

I'm new to SAP BTP Low-Code & No-Code.

Could you please suggest some useful url's.

 

Thanks in Advance,

Rajasekhara
maheshpalavalli
Active Contributor
0 Kudos
Hi Rajasekar,

I would suggest you to start by following this SAP community page: https://community.sap.com/topics/low-code-no-code

Then you can checkout this free learning journey from SAP: https://learning.sap.com/products/sap-build/build-apps

 

Cheers,
Mahesh
S0024185098
Discoverer
Hi Mahesh,

what changes in case the CAP application is based on Javascript instead of TypeScript ?

 

Thanks in advance.

 

Massimiliano.
maheshpalavalli
Active Contributor
0 Kudos
You need to add "-t" while generating the openapi/odata clinet to transpile it to javascript.
UxKjaer
Product and Topic Expert
Product and Topic Expert
I tried your example for the principal propagation, but i'm failing to fetch the destinations. I get an error Error in fetching the token for service destinations: Invalid service credentials: Missing clientid.
I've cloned your repo and run the commands you specify to no luck.
I tried to call the getAllDestinationsFromDestinationService function as well and it's coming up with the same error. I'm unsure of where to add the clientid to make this work properly.

I have created the Process Automation Destination in the subacccount destination via the service instance and then exported and imported into my destination service. But I don't believe this has any impact as I'm not even getting this far.

 
maheshpalavalli
Active Contributor
0 Kudos
Hi Jakob, Just updating the conversation here as you have already solved your issue which is related to destination.

Mahesh
iashishsingh
Participant
0 Kudos
Hi maheshkumar.palavalli

Brilliant blog post on the subject, it has been really helpful! Thank you! However, when trying to generate and use the openapi specification for the Workflows APIs, we are getting a 404 Not Found error when creating a workflow. We followed the generator steps as mentioned in the API docs. We used the createWorflowInstance API but it is always giving a 404 error. We ended up using the cloud sdk connectivity for generating the token for principal propagation and trigger the REST API endpoints for Workflows directly.

Thanks,

Ashish
Labels in this area