SuperAPI AI Directory

messaging

General & other

View repository

Updated 10-16 02:37

About this skill

Messaging — CAP Best Practices

Primary reference: https://cap.cloud.sap/docs/guides/messaging/ Event Mesh: https://cap.cloud.sap/docs/guides/messaging/event-mesh

Defining events in CDS

// In the emitting service
service OrderService {
  entity Orders as projection on db.Orders;

  // Declare events (these become CloudEvents topics)
  event OrderSubmitted {
    orderID   : UUID;
    customer  : String;
    amount    : Decimal(9,2);
    currency  : String(3);
  }

event OrderShipped { orderID : UUID; trackingNr : String; } }


## Emitting events

```js
module.exports = class OrderService extends cds.ApplicationService {
  async init() {
    this.on('submitOrder', this.onSubmitOrder)
    return super.init()
  }

  async onSubmitOrder(req) {
    const { orderID } = req.data

    // ... business logic, DB writes ...

    // Emit the event (persisted in outbox by default in CAP >= 7)
    await this.emit('OrderSubmitted', {
      orderID,
      customer: req.user.id,
      amount:   order.totalAmount,
      currency: order.currency_code
    })

    return { success: true }
  }
}

Consuming events from another service

// In the consuming service
module.exports = class ShippingService extends cds.ApplicationService {
  async init() {
    // Subscribe to events from OrderService (same process or remote)
    const OrderSrv = await cds.connect.to('OrderService')
    OrderSrv.on('OrderSubmitted', this.onOrderSubmitted.bind(this))
    return super.init()
  }

  async onOrderSubmitted({ data }) {
    const { orderID, amount } = data
    // ... trigger shipment process
    console.log(`Preparing shipment for order ${orderID}`)
  }
}

Messaging Kinds — Choosing the right provider

Kind Protocol Best for
enterprise-messaging AMQP Legacy, backward compatibility
event-mesh HTTP/webhooks Production cloud deployments
event-mesh-shared AMQP Shared/hybrid scenarios, multitenant apps

Quick setup (CDS 10+):

cds add event-mesh          # HTTP/webhooks — for production
cds add event-mesh-shared   # AMQP — for hybrid testing

SAP Event Mesh configuration

package.json / .cdsrc.json:

{
  "cds": {
    "requires": {
      "messaging": {
        "kind": "enterprise-messaging",
        "format": "cloudevents"
      }
    }
  }
}

Bind the enterprise-messaging service instance in mta.yaml:

- name: my-cap-app-em
  type: org.cloudfoundry.managed-service
  parameters:
    service: enterprise-messaging
    service-plan: default
    path: ./em-config.json

em-config.json (Event Mesh descriptor):

{
  "emname": "my-cap-app-em",
  "namespace": "my/company/app",
  "version": "1.1.0",
  "options": { "management": true, "messagingrest": true },
  "rules": {
    "topicRules": {
      "publishFilter":  ["*"],
      "subscribeFilter": ["*"]
    },
    "queueRules": {
      "publishFilter":  ["*"],
      "subscribeFilter": ["*"]
    }
  },
  "authorities": ["$ACCEPT_GRANTED_AUTHORITIES"]
}

Topic naming (CloudEvents)

CAP auto-derives the topic from the service and event name:

sap/cap/{namespace}/{service}/{event}

For example: sap/cap/com.acme/OrderService/OrderSubmitted

You can override:

event OrderSubmitted @(topic: 'com/acme/orders/submitted/v1') { ... }

The Outbox pattern (transactional safety)

CAP 7+ uses the outbox by default — events are written to the DB in the same transaction as your data writes, then delivered asynchronously. No lost events on crash.

{
  "cds": {
    "requires": {
      "outbox": true
    }
  }
}

To opt out (fire-and-forget):

this.emit('OrderSubmitted', data, { queue: false })

Local development (file-based mock)

{
  "cds": {
    "requires": {
      "messaging": {
        "kind": "file-based-messaging"
      }
    }
  }
}

Events are written to ~/.cds-msg-box/ — no Event Mesh instance needed locally.

Common mistakes to avoid

  • ❌ Emitting events before the DB transaction commits (use the outbox!)
  • ❌ Forgetting to declare events in CDS — type safety and documentation matter
  • ❌ Subscribing in cds.on('bootstrap', ...) instead of service.init() — order matters
  • ❌ Using generic topic names — namespace them to avoid collisions across apps
  • ❌ Not handling duplicate delivery — Event Mesh delivers at-least-once; make consumers idempotent
  • ❌ Hardcoding the Event Mesh namespace in code — derive from service binding at runtime