Events with CPI, Enterprise Messaging and Node.js app part 2 – Webhooks and CPI OData

CPI_webhooks_Halicki
icon__calendar 2020-05-27

In this article you will learn how to:

  • Create webhook to CPI
  • Consume OData service basing on S/4HANA event

Our journey continues

In the previous part of this blog I showed you how to configure events raised from S/4HANA system and send them to Enterprise Messaging service. In this part we will take a look at event itself. We will create a webhook to our CPI flow where we will fetch Sales Order data from OData service and move it to Node.js app. Don’t worry, I will show you the app in the third part of this blog. Let’s go!

 

What is a webhook?

Let’s say in app A we want to fetch actual data from app B and display it. The most traditional way of achieving this goal would be to query some API in app B. The much better way would be when app B could inform app A when some changes occur (for example new order or change in business partner profile). Then app A would get the changed data only from app B.

Hm, it sounds exactly like our scenario. But how a webhook fits into it?

We have a message in our queue and want to notify CPI that it needs to fetch data of newly created sales order. We will simply create a webhook to CPI, I will show how to do that in a minute.

 

CPI

First let’s take a look at CPI flow:

SAP CPI Flow

 

Get sales order number

In get sales order number step I used a simple Groovy script:

def Message processData(Message message) {

  def body = message.getBody(String.class);

  def jsonSlurper = new JsonSlurper();

  def result = jsonSlurper.parseText(body);

  def val = result.EVENT_PAYLOAD.KEY[0].SALESORDER.toString();

  message.setProperty("SalesOrderNumber",val);

  return message;

}

 

In order to understand the code we need to take a look at event payload itself:

{

  "EVENT_PAYLOAD":{

    "BUSINESSEVENT":"ErF9donAHtqm1WON+3ADaw==",

    "TIMESTAMP":20200520150350,

    "KEY":[{

      "SALESORDER":"0000005734"

    }]

  }

}

 

This is what our S/4 generated after creation of sales order 5734. Now you can easily understand the above Groovy script which uses JSONslurper to traverse event payload.At the end sales order number is saved in propert ‘SalesOrderNumber’.

Add header step

Content-type is set to application/json;IEEE754Compatible=true. It is a necessary header for Node.js app to properly encode JSON payload.

 

 

Get sales order details

This is the proper call to S/4HANA system in order to get all details of processed sales order. In order to make it simple I use a custom CDS with OData service. Metadata looks like this:

 

Sales Order Details

 

As you can see there are only a few fields and it is ok for the purpose of our demo.

OData adapter configuration:

 

OData Connection

 

OData Connection Processing

 

Just remember to configure your Cloud Connector in S/4. Reading OData also requires such configuration.

XML to JSON converter

Will convert XML OData response to JSON (wow).

 

Remove parent

Payload coming from OData service looks like this:

{

  "ZC_SALES_ORDER":{

    "ZC_SALES_ORDERType":{

      "netwr":"255453.00",

      "vbeln":"5734",

      "matnr":"MZ-FG-R300",

      "audat":"2016-06-16T00:00:00.000",

      "waerk":"USD"

    }

  }

}

 

I want to achieve two things here: remove waerk field  (app does not accept it) and send a flat JSON structure. I want the final payload to look like this:

 

{

  "netwr":"255453.00",

  "vbeln":"5734",

  "matnr":"MZ-FG-R300",

  "audat":"2016-06-16T00:00:00.000",

}

So let’s take a look at Groovy script:

def Message processData(Message message) { 

  def body = message.getBody(String.class);
 
  def jsonSlurper = new JsonSlurper();
 
  def result = jsonSlurper.parseText(body);
 
  result.ZC_SALES_ORDER.ZC_SALES_ORDERType.remove("waerk");
 
  body = JsonOutput.toJson(result.ZC_SALES_ORDER.ZC_SALES_ORDERType);
 
  message.setBody(body);
 
  return message;

}

 

And voila! Now the only thing left is to send this message to my app. We will do it in part 3.

 

Let’s create a webhook

As discussed in the second paragraph – we want Enterprise Messaging to automatically propagate event from S/4 to our CPI flow. In webhook subscriptions click create:

Webhook CPI

And let’s add connection to CPI:

 

The final result should look like this:

 

Webhook Subscription Final Result

Now all messages from queue S42_SalesOrder will be propagated to CPI. From technical point of view it’s a simple HTTP POST call.

 

Quick paragraph about queues and topics

If you want to learn more on this topic (hehe) take a look at this documentation:

Long story short – relations between a queue and a subscription app is 1:1. If we wanted to handle multiple subscription apps we would create two queues assigned to one topic and each queue would be consumed by one app. Documentation states that it is possible to have multiple apps consuming one topic but it’s possible only programmatically. I copied the CPI flow and named it SalesOrderOData2. I created another queue and assigned it to the same topic:

Queue Subscriptions Webhook

And a new webhook subscription:

New Webhook Subscriptions

 

Now let’s emit an event from S/4. The result in CPI looks like this:

 

Result in CPI

As you can see we’ve just sent one event to two separate receivers. This way we can notify all the apps that need to be notified about a change in our master system.

Summary

In this article, I showed you how to consume OData service basing on event emmited from S/4HANA system, how to create a webhook and how to propagate one event to multiple systems. In part 3, I will show you a consuming Node.js app in Cloud Platform. I will also send an event directly there and consume OData from the app. See you there!

 

Read also:

  1. SAP CPI Value Mapping Maintenance
  2. SAP CPI: Technical guide to build a single XSLT mapping for multiple input types