Skip to Content
Technical Articles

SAP Cloud Application Programming Model and Enterprise Messaging [5]: CAP-managed events

With other words:

How to
use the keyword
event
in CAP model

Quicklinks:
All Project Files

This blog is part of a little series explaining how to use SAP Cloud Platform Enterprise Messaging with CAP (Cloud Application Programming Model) application

Note: the messaging support in CAP is currently in beta mode

Today we’ll have a look at the keyword “event” in CDS model

In the previous examples, we’ve used a topic to send and receive messages.
That’s just a long string.
In Enterprise Messaging, we’ve either manually created queue and topic, or we’ve let CAP generate them

Our code looked like this

Sending:

srv.emit ('company/customer/care/demo/customer/created', {'myProp': 'My message payload'}) 

Receiving:

srv.on('company/customer/care/demo/customer/created', async (msg) => { 
   console.log('=> Received message : ' + msg.data.myProp)

And the Messaging Dashboard:

Now, CAP not only provides support for messaging and eventing, it also has a reserved keyword in CDS modelling: “event

So let’s create a little sample application in which we use that keyword

managed-service.cds

We define the even in our model.
The name of the event should be carefully chosen, because it will be reused and referenced.
As such, a silly name is always helpful.
Here we also define the structure of the event, i.e. the properties which will be carrying the payload

Note:
Message headers cannot be customized (currently), they’re filled by the framework
You can say: they’re CAP-managed

service ManagedService {

    entity DummyEntity {
        key dummyID : Integer;
    }; 

    event myEventName: { 
       myEventProperty: String; 
    }

   function send() returns String;   
}

Note:
In this example, we still don’t need a data-model

Note: For this example, let’s add a “send” function in the same project, to easier try out the messaging round-trip
In a non-silly environment, you could think of notifying different modules of a bigger project, by why should you send messages to yourself in one little project?

managed-service.js

In the custom handler implementation, we can see the benefit of CAP-managed messaging:

To send a message, we don’t need to construct a correct topic, including namespace etc.
Just use the name of the event, as defined in the CDS model.
CAP will take care of the rest

const event = { 
   myEventProperty: 'my message payload'
}  

srv.emit ('myEventName', event)  

To listen to incoming messages:

srv.on ('myEventName', (msg) => {

Again, no need to handle namespace and topic, just listen to the event as defined in the CDS model

One more benefit:
CAP is enabled to validate the event name
As such, if you write an invalid event name, like “myEventNameee”, then CAP will throw an error on startup.

And another little benefit:
When accessing the event properties, you have one central place to lookup the property names.
Below snippet shows that somebody just had a look into the CDS, before writing the “myEventProperty”

  srv.on ('myEventName', (msg) => {
    console.log ('==> Received msg of type myEventName:' + msg.data.myEventProperty)    

Another bigger benefit:
Everybody knows that it is beneficial to let CAP manage as much as possible

And one huge disadvantage:
Let’s be honest:
We cannot let CAP manage events if we want to listen to events from a backend like S/4 HANA

Reason:
See below

CAP managed queue/topic names

We’ve seen that in case of CAP-managed messaging, we can ignore the namespace and topic stuff, which is tedious, because it is strictly validated by Enterprise Messaging
CAP generates the queue and topic correctly for us, under the hood

Below screenshots show the names, as generated by CAP managed messaging

Generated queue name:

Generated topic name:

We can see that CAP correctly uses the namespace at the beginning
However, CAP also uses whatever it wants to generate a non-silly topic
This is our benefit: we don’t need to care about correct namespace etc
We only use the event name like we defined it in the CDS model

BUT:
If we really NEED to use a topic which is PREDEFINED, e.g. in S/4 HANA, then the CAP-managed-auto-non-silly-name-generation is unfortunately not helpful.

No prob, in such cases just follow tutorial 3

Summary

You can define an event in your CDS model
It isn’t mandatory
If you use it, you can use that name in your custom handler code, when emitting or receiving messages.
Topic is generated under the hood

In those cases, when the topic is predefined by e.g. S/4 HANA backend, then CAP-managed messaging cannot be used

Links

Blog Series:
Intro Blog: CAP and Enterprise Messaging
First Blog: create CAP application to send messages to Enterprise Messaging
Second: create CAP application to receive messages
Extra: Local development

Appendix: All Project Files

manifest.yml

---
applications:
- name: capmanaged
  host: capmanaged
  path: .
  memory: 128M
  buildpacks:
    - nodejs_buildpack
  services:
    - msgcustcare

package.json

{
  "dependencies": {
    "@sap/cds": "^3",
    "express": "^4",
    "@sap/xb-msg-amqp-v100": "latest"
  },
  "cds": {
    "requires": {
      "messaging": {
        "kind": "enterprise-messaging"
      }
    }
  },
  "scripts": {
    "start": "npx cds run"
  }
}

managed-service.cds

service ManagedService {

    entity DummyEntity {
        key dummyID : Integer;
    }; 

    event myEventName: { 
       myEventProperty: String; 
    }

   function send() returns String;
}

managed-service.js

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

module.exports = cds.service.impl ((srv) => {
  
  srv.on ('send', async(req)=>{
    const event = { 
      myEventProperty: 'my message payload'
    }  

    srv.emit ('myEventName', event)  

    return "Successfully sent event of type myEventName"
  })

  srv.on ('myEventName', (msg) => {
    console.log ('==> Received msg of type myEventName:' + msg.data.myEventProperty)    
  })
})
Be the first to leave a comment
You must be Logged on to comment or reply to a post.