Events with CPI, Enterprise Messaging and Node.js app part 3 – Node.js and Enterprise Messaging

Int4 Team
2020-06-03

In this article you will learn how to:

– Consume message from CPI in Node.js app

– Consume external services in Node.js app in Cloud Foundry

– Integrate the app with Enterprise Messaging

The last part

In the previous parts of this series I showed you how to configure Enterprise Event Enablement in S/4HANA and how to combine it with Enterprise Messaging and CPI. In this, last part I will show you how to consume message from CPI in Node.js app. Later on I will enhance the app and consume Enterprise Messaging and OData service directly from there. Let’s go!

CPI -> Node.js

I have built my app in my trial account in Cloud Foundry. I was using Cloud Application Programming model. Let’s take a look at it:

Schema.cds file – basic entity for sales orders:

Namespace ah.app.em;

Entity SalesOrders {
    Key vbeln: String(10);
    matnr: String(40);
    audat: String(26);
    netwr: Decimal(9,&nbsp2);
}

Service.cds file with service definition:

using { ah.app.em as em } from '../db/schema';

@path:'/salesorders'
service SalesOrdersService {

    @readonly entity SalesOrders as select from em.SalesOrders {
        *
    };

    @requires_: 'authenticated-user'
    @insertonly entity SalesOrderInsert as projection on em.SalesOrders;

}

As you can see I have two entities here: SalesOrders for reading all sales orders and SalesOrderInsert for creating them.

Service.js file:

const cds = require('@sap/cds')

module.exports = cds.service.impl ( async function() {

this.on ('CREATE', 'SalesOrderInsert', req => {
    console.log('===> Sales Order ' + req.data.vbeln + ' created')
})

})

When new sales order is created let’s log it so we are sure everything went ok.

Now we are ready to add this endpoint to CPI flow.

I will choose simple http adapter with method POST and endpoint to SalesOrderInsert with basic authentication.

HTTP_Adapter

HTTP_Adapter_2

Now when I create a sales order event will be sent to CPI, CPI will collect details from OData and send it to SalesOrderInsert endpoint.

Enterprise Messaging in Node.js?

Now let’s move on to more fun concept. Instead of triggering event to CPI and collection additional data there – let’s consume it and enrich in Node.js app. Fortunately Enterprise Messaging is supported in CAP and we will take advantage of that. First, let’s create connection to our OData service in S/4.

Connection to OData

In order to consume external service from the app we need to perform few tasks. Make sure you have the following services bound to your app:

  1. Destination service
  2. Connection service
  3. XSUAA service

In Destination create a destination to your on-premise system, in my case it is ‘S42’:

Destination

You will need to add external service definition to your project. In order to achieve it you will need an edmx. file of your service. You can extract it from $metadata of your service. You can use ‘cds import <filename.edmx>’ command in order to load it automatically. The final result will look more or less like this:

Final_result

You will see two files in srv/external directory automatically generated for you.

In package.js you will see this (add uaa manually):

"cds": {
    "requires": {
      "uaa": {
        "kind": "xsuaa"
      },
      "ZC_SALES_ORDER_CDS": {
        "kind": "odata",
        "model": "srv/external/ZC_SALES_ORDER",
        "credentials": {
          "destination": "S42"
        }
      }
    }
  }

‘kind’ refers to type of service, ‘model’ is a file directory and ‘credential/destination’ refers to destination created in destination service (3x destination).

We are ready to consume our OData. But let’s add connect to Enterprise Messaging first.

Enterprise Messaging in Node.js

Make sure you have enterprise messaging instance bound to your app. My whole list looks like this:

Bound_Services

In your package.js file add ‘messaging’ section:

"cds": {
    "requires": {
      "messaging": {
        "kind": "enterprise-messaging"
      },
      "uaa": {
        "kind": "xsuaa"
      },
      "ZC_SALES_ORDER_CDS": {
        "kind": "odata",
        "model": "srv/external/ZC_SALES_ORDER",
        "credentials": {
          "destination": "S42"
        }
      }
    }
  }

And that’s all when it comes to configuration of EM in your app.

Final coding

Now let’s assemble all the pieces. In service.js file:

const cds = require('@sap/cds')

module.exports = cds.service.impl ( async function() {
  
  const { SalesOrderInsert } = this.entities

  //connect to external service (use name from package.js file)
  const zc_sales_service = await cds.connect.to('ZC_SALES_ORDER_CDS')
  
  //consume topic from Enterprise Messaging
  //the topic name was set previously
  this.on('S42/BO/SalesOrder/Created', async msg => {  

    const { ZC_SALES_ORDER } = zc_sales_service.entities
    const tx = zc_sales_service.transaction(msg)

    //collect details from external service
    const result = await tx.run (
       SELECT.one(ZC_SALES_ORDER,['vbeln','matnr','audat','netwr']).where({ vbeln : msg.headers.EVENT_PAYLOAD.KEY[0].SALESORDER })
    )

    console.log('===> Read Details of Sales Order : ' + result.vbeln)
    
    //and save it in database
    return cds.transaction(msg).run(
       INSERT.into (SalesOrderInsert) .entries ({ vbeln : result.vbeln, matnr : result.matnr, audat : result.audat, netwr : result.netwr })
    )

  })

  this.on ('CREATE', 'SalesOrderInsert', req => {
    console.log('===> Sales Order ' + req.data.vbeln + ' created')
  })

})

When you go to Enterprise Messaging cockpit after deployment you will notice that queue and queue subscription were created automatically:

Enterprise_messaging_queue

Enterprise_messaging_queue_subscription

Now when event arrives in Enterprise Messaging it will automatically consumed by our app.

Summary

It was quite a long journey but we have finally reached the end. I showed you how to use S/4 HANA events, consume them in Enterprise Messaging, CPI and Node.js app. I hope you enjoyed the series. Let me know what you think in the comments section below the LinkedIn post!

Read also:

1. How to consume RESTful Enterprise Messaging in ABAP

2. SAP CPI – Combine in Sequence vs Combine Aggregation Algorithm