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

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, 2); }
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.
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:
- Destination service
- Connection service
- XSUAA service
In Destination create a destination to your on-premise system, in my case it is ‘S42’:
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:
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:
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:
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
Popular tags
ABAP int4 INT4 IFTT Int4Interview S/4HANA SAP AIF SAP CPI sap integration