Product Information
Your First End-to-End Tutorial of Event Mesh on SAP Business Technology Platform (China, Shanghai Region)
Here is an end to end hands-on about using SAP Event Mesh on SAP Business Technology Platform (China, Shanghai region, or cf-cn40 landscape). You can find all the code snippets used in this blog post in this GitHub repository.
The process of renaming (from Enterprise Messaging to Event Mesh) and the rollout of the free service plan is still undergoing, and we will update this tutorial according to the latest changes.
💻 Prerequisites:
- Global Account and Subaccount on SAP Business Technology Platform (China, Shanghai Region)
- Entitlements of SAP Event Mesh, SAP Business Application Studio
Set Up Service Instance and Subscription
First, we go to Cloud Cockpit and set up service entitlements, instances, subscriptions and user authorizations.
Entitlement
Assign one of each following entitlement to your Subaccount:
Service | Technical Name | Plan |
---|---|---|
Event Mesh | enterprise-messaging | default |
Enterprise Messaging | enterprise-messaging-hub | standard |
The first entitlement is to create a message client service instance, and the second one is to provide a management cockpit, or dashboard as the name given.
Service instance
In your cf space, create a service instance for Event Mesh
(technical name: enterprise-messaging), with the service plan default
.
In the wizard, you are asked to fill in a JSON-formatted service descriptor (following the Syntax for Service Descriptor), you can copy and paste the following, and change the parameters:
- namespace: <org-name>/<mesage-client-name>/<number>/<queue-name>, following the Syntax for Naming Queues, Topics, and Topic Patterns
- message client name (recommended to be the same as service instance name)
{
"emname": "<message-client-name>", // fill in your message client name
"namespace": "<your-namespace>", // fill in your namespace
"version": "1.1.0",
"options": {
"management": true,
"messagingrest": true,
"messaging": true
},
"rules": {
"queueRules": {
"publishFilter": [
"${namespace}/*"
],
"subscribeFilter": [
"${namespace}/*"
]
},
"topicRules": {
"publishFilter": [
"${namespace}/*"
],
"subscribeFilter": [
"${namespace}/*"
]
}
}
}
🔖 Besides Cloud Cockpit, you can also do this step via CF CLI.
Service key
To create a service key, in the cockpit, select service instance 👉 create service key 👉 just type in the name of the service key 👉 and hit create.
Take a look at the auto-generated JSON-formatted service key, and find the key-value pairs of:
- namespace,
- management API URI, and three messaging API URIs (typically the URI for HTTP REST protocol),
- client id, client secret and token endpoint.
You will make use of them later.
Subscription and role collections
In the cockpit, subscribe to Enterprise Messaging
(technical name: enterprise-messaging-hub), standard
service plan.
Add role collections and assign users for the application subscription. Role collections are already created, so you can assign users, i.e. your SAP account to the collections to get access to Enterprise Messaging.
Now you can go to the application “Event Mesh Dashboard” by clicking the link provided in the subscription and have some explorations, for instance, you can go to the message clients
page, and find the message client you just created when you create your service instance.
Create a queue and test the messaging via the dashboard
Create
🎬 Scenario: you want to watch CCTV New Year’s Gala. You are busy but you don’t want to miss all the comedies. CCTV will send you messages when a performance starts, and the message will tell you if it is comedy.
You need to first create a queue named comedy
. On page SAP Event Mesh Dashboard
👉 on the left menu, select tab Message Clients
👉 go into the tile mymessageclient
👉 tab Queues
👉 click Create Queue
👉 in the pop-out window, fill in the parameters: queue name = comedy, and leave others as default.
Hit Create
, and you can see the queue myorg/mymessageclient/001/category
has been created, with zero messages currently.
🔖 You don’t have to add namespace as a prefix to your queue name as it will be attached.
Test
Go to Test, on the left-hand side, select the queue and message client, fill in the Message Data
parameters, hit Publish Message
. You can see a “published” notification flashing out, and there is one message in the queue now.
📊 Sample Message Data
- Content-Type: application/json
- Body: {“time”: “20210124 21:00:00”, “category”: “music”}
On the right-hand side, select the queue and message client, and hit Consume Message
. You can receive the message data you just published, and the number of messages in the queue goes down to zero.
Create a queue and send message to the queue, via messaging API (postman)
🎬 Scenario: your daughter also watches the show. She wants to know when she can see her idols on the screen, so she is interested in CCTV’s messages about the artists screen time.
To create a queue, Event Mesh provides a type of APIs to manage the queue, queue subscription, etc., REST APIs for Management, to publish and consume messages, the type is REST APIs for Messaging.
We use Postman to send HTTP requests. Remember to find URLs and other values from the service key.
Get access token
Before communicating with Event Mesh services via APIs, we need to get the access token from XSUAA. This Help document can guide you through the process of fetching access token by providing client id and client secret to the token endpoint.
What you need to fill in the postman:
Tab | Key | Value |
---|---|---|
Bar | Method | choose GET |
Bar | URL | <tokenendpoint>?grant_type=client_credentials&response_type=token |
Authorization | Type | choose Basic Auth |
Authorization | Username | <clientid> |
Authorization | Password | <clientsecret> |
Send the request, you will get 200 OK response, with the access_token. The access token needs to be included in the header of the next few requests: Authorization
: Bearer {{access_token}}
.
Create a queue
In the document about API, you can find the API to create queue is PUT /hub/rest/api/v1/management/messaging/queues/{queue}
.
The parameter in URL: {queue}
is the URL encoded queue name with a namespace prefix. e.g. myorg/mymessageclient/001/artist
–> myorg%2Fmymessageclient%2F001%2Fartist
.
What you need to fill in the postman:
Tab | Key | Value |
---|---|---|
Bar | Method | choose PUT |
Bar | URL | <management[0].uri>/hub/rest/api/v1/management/messaging/queues/{queue} |
Authorization | Type | choose No Auth |
Headers | Authorization | Bearer <access_token> |
The body is optional, schema QueueP is defined with default values.
Send the request and you will get the response of 201 Created, with the information of the created queue.
To list the queues, use GET /hub/rest/api/v1/management/messaging/queues
. Instead of Method and Path, all other parameters remain the same. Send the request, you can see all the queues.
Send and consume message via message API
To send a message to a queue, we can find the API in messaging API POST /messagingrest/v1/queues/{queue-name}/messages
. Parameter {queue-name}
in URL again should be URL encoded full name with a namespace prefix.
Tab | Key | Value |
---|---|---|
Bar | Method | choose POST |
Bar | URL | <messaging[protocol=httprest].uri>/messagingrest/v1/queues/{queue-name}/messages |
Authorization | Type | choose No Auth |
Headers | x-qos | sample 0 |
Headers | Authorization | Bearer <access_token> |
Body | raw – JSON | sample {"time": "20210124 21:00:00", "artists": [{"name": "TFBOYS"}, {"name": "Ye Zhang"}]} |
Header x-qos
is the quality of service, 0
means as long as the message is sent, mission completed; 1
means make sure the receiver get at least one message.
For Body, you can choose raw
type, and type in any text, for cloud event you can have a defined JSON format.
The ID of the created message will be returned in the header of the response.
To consume a message from the queue, POST /messagingrest/v1/queues/{queue-name}/messages/consumption
. Use the same header settings, and leave the body blank.
All postman config files can be found in the folder ./apis
.
Create a topic, and publish messages to the topic
🎬 Scenario: if CCTV only sends one type of message, performance, containing the performers and category information that you and your daughter care about. to prevent that one message will be retained until you or your daughter consumes it, you two decide to maintain two personal queues. and subscribe to the performance topic, aka queue subscription.
artist
via dashboard
Create a topic (queue subscription) for You can subscribe via the dashboard. Note that the queue can only subscribe to topics that follow the rules defined in the service descriptor. here it means the topic should have the same namespace prefix as the queue.
Publish messages to the topic
Send a message to the topic and you will find the queue artist
receives the message.
In the postman, we use API POST /messagingrest/v1/topics/{topic-name}/messages
to send the request.
Tab | Key | Value |
---|---|---|
Bar | Method | choose POST |
Bar | URL | url encoded <messaging[protocol=httprest].uri>/messagingrest/v1/topics/{topic-name}/messages |
Authorization | Type | choose No Auth |
Headers | x-qos | sample 0 |
Headers | Authorization | Bearer <access_token> |
Body | raw – JSON | sample {"time": "20210124 21:05:00", "name": "A Funny Comedy", "category": "comedy", "artists": [{"name": "Ling Jia"}], "status": "START"} |
In the dashboard, you will find that the number of messages in the queue artist
increases by 1.
category
via APIs
Create queue subscription for queue Via management APIs, in postman, we use PUT /hub/rest/api/v1/management/messaging/queues/{queue}/subscriptions/{topic}
.
Tab | Key | Value |
---|---|---|
Bar | Method | choose PUT |
Bar | URL | URL encoded <management[0].uri>/hub/rest/api/v1/management/messaging/queues/{queue}/subscriptions/{topic} |
Authorization | Type | choose No Auth |
Headers | Authorization | Bearer <access_token> |
Parameters in URL queue
and topic
they all need to be encoded with prefix. Leave the body blank.
If the topic creation successfully proceeds, the response will be 201 Created, with the names of the queue and the topic as the body.
The current architecture:
architecture: adopted from SAP Help Portal
Publish messages to the topic and consume the messages from two queues via APIs
Send a message to the topic.
Tab | Key | Value |
---|---|---|
Bar | Method | choose POST |
Bar | URL | URL encoded <messaging[protocol=httprest].uri>/messagingrest/v1/topics/{topic-name}/messages |
Authorization | Type | choose No Auth |
Headers | x-qos | sample 0 |
Headers | Authorization | Bearer <access_token> |
Body | raw – JSON | sample {"time": "20210124 21:00:00", "name": "Go, Amigo and Hi, Motherland Mash Up", "category": "music", "artists": [{"name": "TFBOYS"}, {"name": "Ye Zhang"}], "status": "START"} |
You can see both of the queues can receive the message.
Let’s consume the message from the two queues.
[optional] Develop producer and consumer applications on SAP BTP
In this tutorial Tutorial: Develop a Messaging App on SAP BTP, you can learn how to develop Node.js-based and Java-based message cunsomer or producer applications on BTP.
SAP has provided full collections of development tool sets like Node.js packages, Java libraries, and other programming languages, to help you develop messaging applications logic in XS Advanced (i.e. SAP HANA Extended Application Services advanced model, the Cloud Foundry PaaS with enhancements provided by SAP)).
JavaScript
For development in JavaScript, you can make use of Standard Node.js Packages for XS Advanced:
- @sap/xb-msg: Provides messaging capabilities with a message broker. This package supports the RabbitMQ message broker with the following protocols: amqp v091, amqp v100, mqtt v311
- @sap/xb-msg-env: Provides the functions needed to set up messaging client options from Cloud Foundry or XS advanced environment variables
- @sap/xsenv: Utility for easy setup and access of XS Advanced environment variables and services
Java
For development in Java, you can leverage SAP Cloud Application Programming Model (libraries: com.sap.cloud.servicesdk.xbem.*), following Java Message Service (JMS) 2.0 specification, :
- MessagingService,
- MessagingServiceJmsConnectionFactory,
- …
For the SAP Cloud SDK, features of Event Mesh for both of JavaScript and Java is planned, and its progress depends on CAP.
Create a webhook (nodejs), deploy it (application studio), and subscribe your webhook to a queue
🎬 Scenario: now you don’t want to check the queue from time to time for the comedy performances, you want to build a webhook which can send you notification when there is a performance message from the CCTV, and the performance is comedy.
Instead of consumers fetching messages from the message client, if we add a webhook, the message client will POST the messages from the specified queue to the specified URL. Here we only create a webhook for the queue comedy
.
The current architecture of a webhook looks like this:
architecture with webhook: adopted from SAP Help Portal
Create and deploy
Go to application studio 👉 create a Full Stack Cloud Application
Dev Space named emtester
, go into the dev space 👉 Create Project 👉 select template and target location Basic Multitarget Application
👉 Start
👉 type in the project name webhook
, finish.
Delete all the auto-created files and folders. create file manifest.yml
. copy and paste the following content:
---
applications:
- name: webhook
routes:
- route: <host-name>.<domain>
path: .
memory: 128M
Replace the name with your app name, route with your host name concatenated with your custom domain, e.g. webhook.exercise.sap-samples.cn40.apps.platform.sapcloud.cn
.
If you don’t know which domain you can make use of, open terminal 👉 cf login
👉 choose the targed org and space 👉 cf domains
👉 find one.
In the terminal, go to the current folder, npm init
and hit return to get all the default values. type in ok. You will find the file package.json
is created, and it requires a main page index.js
.
Install the two Node.js packages we will use, express and body-parser, by npm install express body-parser
🔖 What do these two packages do?
express is a Node.js package to provide small, robust tooling for HTTP servers, making it a great solution for single page applications, web sites, hybrids, or public HTTP APIs.
body-parser is a Node.js package to parse incoming request bodies in a middleware before your handlers, available under the req.body property.
We want to add start script, so add key-value pair start
in the scripts
, and delete the test
from the scripts
. Finally the file package.json
will look like:
{
"name": "webhook",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1"
}
}
Now let’s work on the file index.js
, just create it and copy and paste:
const express = require("express")
const bodyParser = require("body-parser")
const app = express()
const PORT = process.env.PORT || 8080
app.use(bodyParser.json())
app.get('/', (req, res) => {
res.status(401).send('Hey, this is a webhook - we only receive POST!')
})
app.post('/', (req, res) => {
if(req.body.category == "comedy") {
console.log(' ', req.body)
res.status(200).send(' ' + req.body.name).end()
}
else {
console.log(' ', req.body)
res.status(200).end()
}
})
app.listen(PORT, () => console.log(` Server running on port ${PORT}`))
[Optional] If you want to test the app in local terminal, go to the project root, run
npm start
, and in a new tab use curl to send request to localhost:curl -H 'Content-Type: application/json' -d'{"time": "20210124 21:00:00", "name": "Go, Amigo and Hi, Motherland Mash Up", "category": "music", "artists": [{"name": "TFBOYS"}, {"name": "Ye Zhang"}], "status": "START"}' http://localhost:8080/ curl -H 'Content-Type: application/json' -d'{"time": "20210124 21:05:00", "name": "A Funny Comedy", "category": "comedy", "artists": [{"name": "Ling Jia"}], "status": "START"}' http://localhost:8080/
The first request will leave a log with sad face, and the second request will make the webhook app to log a happy face.
Deploy it onto BTP. In the terminal, go to project root, run cf push
.
Test the webhook by sending a message to the webhook with the postman (or curl from the terminal).
All the code snippets can be found in the folder ./webhook/
.
Create webhook subscription
Go to dashboard 👉 go into our message client 👉 choose webhooks
tab 👉 creat webhook subscription 👉 in the pop-up window, fill in queue name, webhook url and other parameters 👉 click create
.
The process of activation will be completed by making a handshake between the message client and your webhook application, during the first message exchange.
performance
, and read the logs of the webhook application webhook
Send a message to the topic Then publish a message to the topic performance
again. You will find, artist
queue has lined up with messages to be consumed, while category
queue has zero messages. It is because the messages to the latter queue have been forwarded to the webhook.
Go to cf logs webhook
to see the logs, you will find that all the two messages have been logged, labelled with an interested or not interested label.
If you bind the SAP Application Logging Service to your webhook application (here is the How-To on SAP Help Portal), you can also observe the logs on the cockpit.
Wrap-up
In this blog post, we first set up SAP Event Mesh service instance and subscription on Cloud Cockpit. Then, we tried to create queues via SAP Event Mesh Dashboard and HTTP API calls, and we tested the messaging of the queues by publishing messages to the queues and consuming the messages. We also created a queue subscription and tested it by publishing messages to the topic and consume them from the queues. Next, we build a webhook, deployed it to the BTP CF environment, and subscribe it to one of the queues. By now, you have walked through a full end-to-end scenario of SAP Event Mesh on cn40.
If you have further questions, feel free to leave me a comment here, or submit a question in the Q&A area on this topic.
Hi Sindy,
Nicely written and well explained.
However some images are not clear (probably because of links poiting to SAP's internal github account ). Also github repository link (first paragraph) is pointing to sap's internal github corporate account. Many wont be able to access that url. not sure if that was intenational.
Thanks, Ajit
Hi Ajit,
Thank you for your comments!
Also thank you for pointing out the picture issue. I didn't notice that I also attached the link of the internal github repo to some pictures. Now I have removed the hyperlinks.
Best regards,
Sindy
Hi Sindy,
Pictures are more clear now. Thank you for updating them. Just one last request. GitHub Repository link still points internal account.
May be you could put the repository here so that everyone can access: https://github.com/SAP-samples
Best Regards, Ajit
Hi Ajit,
Thanks for your suggestions, good idea!
I will figure out how to put my repo to https://github.com/SAP-samples.
Best regards,
Sindy
Hi Sindy,
Thanks for sharing in detailed blog on SAP Event mesh.
Thank you,
Syam
Hi Syam,
Thank you so much for your reading and replying!
Best,
Sindy
Hi Sindy Zhan ,
Thanks for great info.
I have a question: what if I want to consume a particular message, not all messages, do you have any ideas how we can achieve that?
I've checked the SAP Event Mesh Messaging API https://help.sap.com/doc/3dfdf81b17b744ea921ce7ad464d1bd7/Cloud/en-US/messagingrest-api-spec.html, but it seems it can consume all messages. I couldn't see anywhere I can consume a particular message.
Regards,
Minh
Hi Sindy,
Very informative and detailed blog. Looking forward to more blogs .
Thanks
Shyam
Hi Sindy,
I don't have Enterprise Messaging in list of entitlements , is there a way to get this?
best regards,
ebsor
Hi Zaby,
Which landscape are you using? If it is AC-Canary or other SAP-operated landscapes, as an internal user you can assign yourself entitlements in the control center. If it is AC-Live, you should open a ticket to CDC and let them assign entitlements for you.
Best,
Sindy
Hi Sindy Zhan
Is Event Mesh available in trial account(US East) also.I could subscribe to it but when i click on go to application its showing Not Found.I created instance,service key and assigned user to role colllection.
Best Regards,
Keerthana
Hi Sindy,
I am struggling & confuse on the JSON file creation which we need to uploaded during the creation of DEV instance for SAP Event Mesh.
Could you pls. help me to create the same by sharing the details like what to put in JSON file & from where i get these required details.
Thanks.
Hello colleagues,
Sindy, thanks for the comprehensive tutorial.
I keep getting the following error when I try to push the app towards cloud foundry (I removed some stuff in the brackets for security reasons):
What is going wrong? Do I need to create a compatible domain first?
Best
Carsten
Hi Sindy
Thanks for the very comprehensive post. I am finding it very useful.
I do have one issue though. When PUTing the request to create a message queue via Postman, I get an Unauthorised message, even though I have retrieved a bearer token successfully.
Any idea why?
Thanks
Ian
Hi Ian,
Thank you for reading the blog post and share your feedback!
Have you tried creating key-value pair for the token as an entry in the header, like this:
Key: "Authorization"
Value: "Bearer <the token>"
Best regards,
Sindy
Hi Sindy
Thanks for the quick response.
I am using the key value pair as suggested, yes. I can retrieve the bearer token fine but cannot then interact with the service.
Regards
Ian
Hi Sindy
An update to the above.
We are using two message clients and I wasn't aware the client id/secret were specific for each one.
Also, the URL being used was not correct. I needed the enterprise-messaging-pubsub one and the not the one I was using that specified the tenant instance at the beginning.
All good now.
Thanks
Ian
Hi Sindy Zhan
How interesting!
One question: Is there any way to reserve the message even after consumed by webhook? Because I want to build a webhook just for logging the messages, and do not want any impact on original subscription.
Thanks
Sensen
Hi Sindy,
Thanks for the informative Blog.
I was trying to implement EDA through Enterprise Event Enablement by triggering standard S4 events from API business hub to Event Mesh and then passing the payload to the Nodejs service using Webhook subscription i.e. the same service in the blog.
S4 (on-premise) -> Event Mesh -> Nodejs Service using Webhook subscription.
When I am trying to trigger a standard event on S4 side (PurchaseOrder), I am only getting an empty payload as an output in the logs of the Nodejs service.
Expected Payload:
{"type":"sap.s4.beh.purchaseorder.v1.PurchaseOrder.Changed.v1","specversion":"1.0","source":"/default/sap.s4.beh/E21CLNT200","id":"0e1e2ed4-53db-1edd-b1e0-a40c6949848e","time":"2023-03-20T09:53:56Z","datacontenttype":"application/json","data":{"PurchaseOrder":"4500000185"}}
Also, while trying to publish the event from a rest client (Postman), I am getting the expected payload on the Nodejs logs as described in the blog. I believe, the Nodejs service is not able to extract the payload from the Event Mesh queue hence the empty payload.
Could you please guide me with the process/steps to be followed for achieving the above.
Thanks
Ribhav
Hello,
when we use standard S4 events is it possible to configure which fields are transferred with the event?
I want more than the sales order.
BR
Wolfgang