SAP Event Mesh Messaging in BTP a Use Case

This blog gives a sample use case of SAP Event Mesh Messaging service in  SAP BTP using Cloud Foundry environment.

Use Case:

Basically a messaging publisher & consumer application was built using SAP Event Mesh as middleware and SAP HANA Cloud Database to store data from the message and UI5 App for visualization.

Framework/Technologies used:

  1.  SAP HANA Cloud Database.
  2.  SAP Event Mesh
  3.  Node.js Express service deployed in SAP BTP Cloud Foundry runtime.
  4.  UI5 application deployed in SAP BTP Cloud Foundry runtime.

Overview

Below are various steps involved in SAP BTP  :

1.Create SAP Event Mesh Instance , I had used dev plan from Trial account.

2.Create SAP HANA Cloud Database instance and table EMRECEIVE for storing messages info & also create SAP HANA Schemas & HDI Containers service for interaction with HANA Database from Node.js service.

3.Create Express Node.js service in Cloud Foundry to publish messages into SAP Event Mesh  Queue and consumer Webhook subscription service to save data into table EMRECEIVE.

4.Create Destination service in SAP BTP for Express Node.js service created above since we will be using this destination service in UI5 application to overcome CORS policy issue .

5.Create UI5 application and deploy in Cloud Foundry consuming the Destination service.

1.SAP Event Mesh Instance:

I had used “dev” plan for SAP Event Mesh Instance in BTP Trial. Instance can be created by following below tutorial by PRADEEP PANDA

SAP Event Mesh Instance creation

Below is the Event Mesh instance “sapem” which i had created.

Instance “sapem” will activate SAP Event Mesh UI. Create Queue “HANAQUEUE” .

Below is “Service Descriptor” info of SAP Event Mesh instance.

{ "options": { "management": true, "messagingrest": true }, "emname": "mesh"
}

2. SAP HANA Cloud Instance:

Create SAP HANA Cloud Instance by following below tutorial by Thomas Jung.

Deploy HANA Cloud

I had created an instance of name “HANA”.

Create a table “EMRECEIVE” with fields ID,DATA,Comments which is used to store data coming from SAP Event Mesh Webhook subscription.

Create “SAP HANA Schemas & HDI Containers” service instance named “hanapi”  which acts as a HANA Service broker ,in order to interact with HANA Cloud instance in Node.js application in the next step.

Follow below steps as in SAP help for service creation.

Set Up a Schema or an HDI Container

3.  Express Node.js Application deployment in Cloud Foundry Runtime for Publisher & Consumer service:

From SAP Business Application Studio create Node.js project, all the code can be found in my below github repository.

Express project for Publisher & Consumer ( Webhook subscription ) service in github.

I had named this service as “hanapi-srv” as in manifest.yml file.

# Generated manifest.yml based on template version 0.1.0 # appName = hanapi
# language=nodejs
# multitenancy=false
---
applications:
# -----------------------------------------------------------------------------------
# Backend Service
# -----------------------------------------------------------------------------------
- name: hanapi-srv random-route: true # for development only path: app buildpack: nodejs_buildpack command: node server.js

You can deploy this application into cloud foundry from SAP Business Application Studio command line using  cf login & cf push commands. To get idea on Cloud foundry see Fundamentals of SAP BTP by Marius Obert

We need to bind this “hanapi-srv” with HANA Container Instance service ( hanapi ) & SAP Event Mesh Instance ( sapem )since we are using these services inside the “server.js” file of “app” folder of this express.js service.

Let me give a brief explanation on the code written in “server.js” file in “app” folder.

Below libraries are used in the service

express             –> For building web application frame work

@sap/xsenv      –> To fetch info of HANA instance & SAP Event Mesh instance info which are binded  to this application.

@sap/hdbext     –> Middleware to connect HANA cloud instance.

axios                   –> For Asynchronous JavaScript calls.

const exp = require('express'); const xenv = require('@sap/xsenv');
const hdbext = require('@sap/hdbext');
const axios = require('axios');
const app = exp();

In the code just concentrate on below URL path’s only which we will be using.

/emsend –> This URL path will be used in UI5 application in a table display to fetch data from HANA table EMRECEIVE. Below code is self explanatory.

//get data from EMSEND
app.get('/emsend', (req, res) => { req.db.exec('SELECT * FROM "DBADMIN"."EMRECEIVE"', (err, rows) => { if (err) { res.type('text/plain').status(500).send(err); }; res.status(200).json(rows); });
});

Publisher service /push –> This URL path will be used in UI5 application in a Simple Form UI to push message data into SAP Event Mesh Queue “HANAQUEUE“. Below is the code

//function for message push
let eventpush = async (baseuri, accesstok, body) => { await axios.post(baseuri, body, { headers: { 'content-type': 'application/json', 'Authorization': `Bearer ${accesstok}`, 'x-qos': 1 } }).then(response => { console.log('Queue API success'); console.log(response); }).catch(err => { console.log('err in Queue API'); console.log(err); });
}; //function for token'
let eventmeshfun = async (token, tokenurl, baseuri, body) => { await axios.post(tokenurl, {}, { headers: { 'Authorization': `Basic ${token}` } }).then(response => { console.log('response trigger'); console.log(response);//here we will get access token" //post message to Queue API eventpush(baseuri, response.data.access_token, body) }).catch(err => { console.log('err'); });
}; //push messages to Queue
app.post('/push', (req, res) => { let lmessages = msgsrv['enterprise-messaging'].messaging; let lhttp = lmessages.filter(lmessage => lmessage.protocol[0] == 'httprest'); let tokenurl = lhttp[0].oa2.tokenendpoint + '?grant_type=client_credentials&response_type=token'; let baseuri = lhttp[0].uri + '/messagingrest/v1/queues/HANAQUEUE/messages'; const username = lhttp[0].oa2.clientid; const password = lhttp[0].oa2.clientsecret; const token = Buffer.from(`${username}:${password}`, 'utf8').toString('base64'); eventmeshfun(token, tokenurl, baseuri, req.body); res.send('Data Push Done');
});

In above code path /push i had used SAP Event Mesh Rest API “/messagingrest/v1/queues/HANAQUEUE/messages” to publish messages into Queue “HANAQUEUE” .

Details related to various REST API’s can be found in below links.

SAP Help Event Mesh Rest API usage.

SAP Help Event Mesh Rest API complete info.

Consumer Service /pull –> This URL path will be used in SAP Event Mesh Web UI for Webhook subscription to save data into HANA Table “EMRECEIVE” .

If we look at the code in /pull it is just the Insert records into EMRECEIVE table.

////Webhook subscription from QUEUE
app.post('/pull', (req, res) => { let element = req.body; req.db.exec('INSERT INTO "DBADMIN"."EMRECEIVE" VALUES(?,?,?)', [element.ID, element.DATA, element.Comments], (err) => { if (err) { console.log(err); } });

4. Create a Destination service in SAP BTP for above Express.js service:

Created a destination service named “geteventmesh” using the domain hostname of above express.js service since we will be using this destination in UI5 app .

5. UI5 application for Publishing & consuming data from SAP Event Mesh:

Below is the link for UI5 application from my GitHub repository. This is a very simple single page application deployed in Cloud Foundry nothing fancy in UI complexity like multi pages etc.

UI5 MTA App github

Deployed UI5 app in cloud foundry

HANA Table data

UI5 App ,URL can be found under application ui5-approuter application

Table UI will display data from table EMRECEIVE during Initial & Refresh Button click of UI. Form UI will push data into SAP Event Mesh Queue “HANAQUEUE” and the Webhook subscription attached to that queue will update data in the HANA table.

HANA Table Updated from SAP Event Mesh Webhook subscription URL path /pull.

On Refresh button click data fetch from HANA table

Below is the overview level explanation of code. Consider only folder “ui5app”.

xs-app.json  –> it contains destination geteventmesh usage for reaching URL paths /emsend ( to fetch data from HANA table ) & /push ( to push message data to SAP Event Mesh )

 { "source": "^/emsend", "target": "/emsend", "destination": "geteventmesh" }, { "source": "^/push", "target": "/push", "destination": "geteventmesh" }

In this folder path ui5app –> webapp –> controller –> V1.controller.js  is view controller to call different services.

sap.ui.define([ "sap/ui/core/mvc/Controller", "sap/ui/model/json/JSONModel"
], /** * @param {typeof sap.ui.core.mvc.Controller} Controller */ function (Controller,JSONModel) { "use strict"; return Controller.extend("ui5app.controller.V1", { onInit: function () { //get data from HANA Service destination service let oModel = new JSONModel(); let uri = '/emsend'; let that = this; jQuery .ajax({ url: uri, type: "GET", dataType: "json", success: function (response) { let data = { hana : ''}; data.hana = response; oModel.setData(data); console.log(oModel); that.getView().setModel(oModel,"HANAMODEL"); }, error: function (err) { console.log(err); } }); }, onPush: function (evt) { let uri = '/push'; let that = this; let data = { "ID":'',"DATA":'',"Comments":''}; data.ID = this.getView().byId("ID").getValue(); data.DATA = this.getView().byId("DATA").getValue(); data.Comments = this.getView().byId("Comments").getValue(); jQuery .ajax({ url: uri, type: "POST", dataType: "json", data: data, success: function (response) { console.log(response); }, error: function (err) { console.log(err); } }); }, onPress: function (evt) { let uri = '/emsend'; let that = this; jQuery .ajax({ url: uri, type: "GET", dataType: "json", success: function (response) { let oModel = that.getView().getModel("HANAMODEL"); let data = { hana : ''}; data.hana = response; oModel.setData(data); console.log(oModel); // that.getView().setModel(oModel,"HANAMODEL"); }, error: function (err) { console.log(err); } }); } }); });

On Refresh button click ,onPress event will be triggered and similarly on click of Push To Event Queue button onPush event will be triggered which will be pushing the data into SAP Event Mesh.

So this a sample use case for SAP Event Mesh Messaging application ,we can build creative applications using just the different services provided in SAP BTP.