Overview

The PubSub service allows other services on the YaaS platform to integrate with the use of asynchronous messages. These messages represent information about business events, such as a new order, or when a user resets the password. To exchange the specific business events, services establish message channels, known as topics. The PubSub service supports both a push- and a pull-style communication models. You can choose if you want the service to push the messages, or if you prefer to proactively pull them from the topics. The topics support publishing and consuming events on behalf of multiple tenants.

Features

Use the PubSub service to:

  • Create, list, and delete topics
  • Publish events, such as, new orders, price changes, and password resets, to this topic
  • Consume the events
To create topics and publish events, subscribe to the Events package on the YaaS Market. If you only want to consume messages (push or pull), no subscription is required.

The following diagram shows the PubSub service at a high level. The term "client" refers to the concept of a YaaS Client that you use to interact with YaaS APIs.

PubSub Overview

Basic steps to integrate an event publisher and a consumer

  1. As a publisher, create a topic.
  2. [Optional] If you expect that other clients will consume messages from the topic, document the name of the topic, and the schema of the event payload. For an example of how to document events, see the Order service API documentation.
  3. Publish events to the topic. Make sure you employ the same client that you used to create the topic. Currently, only the owner of a topic can publish to it.
  4. As a consumer, find the documentation provided by the publisher, and take note of the name of the topic from which you want to consume events, and information about the event payload schema.
  5. As a pull consumer, continuously read events from the topic, and explicitly acknowledge when they have been processed.
  6. As a push consumer, create a subscription to the topic. The subscription includes an HTTPS endpoint to which PubSub sends messages. The subscriber's HTTP response implicitly acknowledges the event.

Benefits

  • Location transparency: The publisher and the consumer do not need to know each other's location.
  • Temporal decoupling: The publisher and the consumer do not need to be available at the same time.
  • Independence: The publisher and consumer can be deployed, maintained, and scaled independently.

Common use cases

  • Asynchronous workflows: For example, the Order service publishes order events that can be asynchronously processed by downstream fulfillment systems.
  • Event notifications: For example, the OAuth2 service publishes subscription events. Pull these events from the appropriate topic, or subscribe to it, to know when someone subscribes to your package.


API Reference

/topics

/topics

post

Create a new topic.

A subscription to the Events package is required.

/topics/{topicOwnerClient}

get

List all topics of the calling client. Returns an empty list if there are none.

A subscription to the Events package is required.

/topics/{topicOwnerClient}/{eventType}

delete

Delete a topic.

A subscription to the Events package is required.

/topics/{topicOwnerClient}/{eventType}/publish

post

Publish an event to the given topic.

A subscription to the Events package is required.

/topics/{topicOwnerClient}/{eventType}/read

post

Read the next event from the given topic. May return an empty response. Returned events must be committed explicitly, if autocommit is not enabled. For more information about how to customize the read behavior, and event delivery guarantees, see the PubSub service documentation.

A subscription to the Events package is not required.

/topics/{topicOwnerClient}/{eventType}/commit

post

Commits events.

A subscription to the Events package is not required.

/topics/{topicOwnerClient}/{eventType}/subscriptions

get

List all subscriptions of the calling client to the given topic. Returns an empty list if there are none.

A subscription to the Events package is not required.

post

Create a new subscription.

A subscription to the Events package is not required.

/topics/{topicOwnerClient}/{eventType}/subscriptions/{name}

get

Get subscription details.

A subscription to the Events package is not required.

delete

Delete a subscription.

A subscription to the Events package is not required.

patch

Update a subscription. The properties username, password and endpoint can be changed. The subscription name cannot be changed.

A subscription to the Events package is not required.


Topic Management

This section shows how to use the topic management API of the PubSub service:

  • Create a topic
  • Delete a topic
  • List topics

For this and the following sections, see the API reference for more detailed information about request parameters and payloads, and response codes and bodies.

You need an access token from the OAuth2 service to call the PubSub APIs. For more information, see the Grants document.

Create a new topic

Use the /topics endpoint to create a new topic. The name of the new topic always follows the pattern {topicOwnerClient}.{eventType}, where topicOwnerClient is the name of your YaaS client. You can request the access token outside the scope of a tenant (scope=hybris.no_tenant). The topic belongs to the client that created it, not to the specific tenant.

You can create up to 40 topics per client.

Example

The following example demonstrates how to create a topic:

curl -X POST \
     -H "Authorization: Bearer access_token" \
     -H "Content-Type: application/json" \
     -d '{ "eventType": "myEventType" }' \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics

This is an example response:

{
  "links": [
    {
      "rel": "self",
      "href": "https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType"
    },
    {
      "rel": "publish",
      "href": "https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/publish"
    },
    {
      "rel": "read",
      "href": "https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/read"
    },
    {
      "rel": "commit",
      "href": "https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/commit"
    }
  ]
}

Delete a topic

Delete a topic using the /topics/{topicOwnerClient}/{eventType} resource.

Example

The following example demonstrates how to delete a topic:

curl -X DELETE \
     -H "Authorization: Bearer access_token" \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType
If you delete a topic, all push subscriptions to this topic are deleted as well.

List all topics

List topics using the /topics/{topicOwnerClient} resource.

Example

This is an example of how to list topics:

curl -H "Authorization: Bearer access_token" \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient

This is an example response:

[
  {
    eventType: "myEventType1",
    href: "https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType1"
  },
  {
    eventType: "myEventType2",
    href: "https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType2"
  }
]


Push Subscription Management

This section shows you how to use the push subscription management API of the PubSub service:

  • Create a subscription
  • Get subscription details
  • List subscriptions
  • Update a subscription
  • Delete a subscription

Create a new subscription

Use the /topics/{topicOwnerClient}/{eventType}/subscriptions endpoint to create a new subscription to a topic.

Example

The following example demonstrates how to create a subscription:

curl -X POST \
     -H "Authorization: Bearer access_token" \
     -H "Content-Type: application/json" \
     -d '{ \
           "name": "mySubscription", \
           "pushConfig": { \
             "endpoint": "https://domain.com/endpoint", \
             "basicAuth" : { \
               "username": "user", \
               "password": "password" \
             } \
           } \
         }' \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/subscriptions
The push endpoint must be an HTTPS URL.

Get subscription details

Use the /topics/{topicOwnerClient}/{eventType}/subscriptions/{subscriptionName} endpoint to get subscription details.

Example

This is an example of how to get subscription details:

curl -H "Authorization: Bearer access_token" \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/subscriptions/mySubscription

This is an example response:

{
  "name": "mySubscription",
  "pushConfig": {
    "endpoint": "https://domain.com/endpoint",
    "basicAuth": {
      "username": "username",
      "password": "<private data hidden>"
    }
  }
}

List subscriptions

Use the /topics/{topicOwnerClient}/{eventType}/subscriptions endpoint to list your subscriptions for a given topic. This returns only the subscriptions of the calling client.

Example

This is an example of how to list subscriptions:

curl -H "Authorization: Bearer access_token" \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/subscriptions

This is an example response:

[
  {
    "name": "mySubscription1",
    "href": "https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/subscriptions/mySubscription1"
  },
  {
    "name": "mySubscription2",
    "href": "https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/subscriptions/mySubscription2"
 }
]

Update a subscription

Use the /topics/{topicOwnerClient}/{eventType}/subscriptions/{subscriptionName} endpoint to update the subscription details.

Example

This is an example of how to update a subscription:

curl -X PATCH \
     -H "Authorization: Bearer access_token" \
     -H "Content-Type: application/json" \
     -d '{ \
           "pushConfig": { \
             "endpoint": "https://domain.com/endpoint", \
             "basicAuth" : { \
               "username": "user", \
               "password": "password" \
             } \
           } \
         }' \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/subscriptions

You can update these individual properties of a subscription: username, password, endpoint.

curl -X PATCH \
     -H "Authorization: Bearer access_token" \
     -H "Content-Type: application/json" \
     -d '{ \
           "pushConfig": { \
             "endpoint": "https://domain.com/endpoint" \
           } \
         }' \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/subscriptions
You cannot update the subscription name.

Delete a subscription

Use the /topics/{topicOwnerClient}/{eventType}/subscriptions/{subscriptionName} endpoint to delete a subscription.

Example

The following example demonstrates how to delete a subscription:

curl -X DELETE -H "Authorization: Bearer access_token" \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/subscriptions/mySubscription


Event Publishing

This section shows you how to publish events to a PubSub topic.

Publish an event

Use the /topics/{topicOwnerClient}/{eventType}/publish endpoint to publish an event. You must request the access token on behalf of the tenant that owns the event data. You cannot publish events on behalf of another tenant. For more information about multi-tenancy in the PubSub service, see the Security section. The request body must contain the event payload. Optionally, it may include metadata in the form of arbitrary key-value pairs.

Publish request example

The following example demonstrates how to publish an event:

curl -X POST \
     -H "Authorization: Bearer access_token" \
     -H "Content-Type: application/json" \
     -d '{ \
           "metadata": { \
             "version": "1" \
           }, \
           "payload": "myEventPayload" \
         }' \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/publish

The topic must be explicitly created before you can publish an event to this topic. For more information about how to create a topic, see the Create a New Topic document.

Limitations

The maximum allowed size of the event payload is 50KB. Additionally, the combined number of characters for key-value pairs of the optional metadata cannot exceed 10,000.

The PubSub service persists successfully published events for 48 hours. After that time, they are deleted and cannot be recovered again.


Push Delivery

For consuming the events, the PubSub service offers both push and pull message delivery. You can choose if you want the service to push the messages, or if you prefer to proactively pull them from the topics.

Push message delivery

Use the push subscription API and subscribe to a PubSub topic to receive the events. Each subscription must specify an HTTPS endpoint that receives the events. The subscriber implicitly acknowledges an event by responding with a success HTTP response (2xx). All other responses (4xx and 5xx) are considered a non-successful delivery. Additionally, the subscriber must respond within 5 seconds. Otherwise, the PubSub service also considers this a non-successful delivery. If this is the case, the service will attempt to resend the event for up to 48 hours. If it cannot be delivered during this time, the event is discarded. The PubSub service sends single events only and does not support batch delivery of multiple events.

You can subscribe to a topic with the same subscription name only once per client.
When you delete a topic, all corresponding subscriptions are deleted, too.
If you change the client credentials of the subscription owner without updating PubSub, the PubSub service does not send events.
Follow these steps to update the subscription owner's client credentials and continue receiving events from PubSub:
  1. Generate new client credentials without deleting the old credentials.
  2. Obtain an access token using the newly-generated client credentials.
  3. Use the obtained access token to update all push subscriptions that the client owns.
  4. Delete the old client credentials 48 hours after updating the push subscriptions.

Security

Provide an endpoint in the form of an HTTPS URL secured with Basic Authentication. Provide both the username and password in the subscription request.

Rate limiting

The PubSub service dynamically limits the sending rate based on the number of successful and non-successful delivery attempts over a specific period of time. This ensures that the subscribers can manage the event flow.

Schema

A subscriber endpoint expects an HTTPS request with a POST method. The request contains the event data as the request body. See the schema of the event here.


Pull Delivery

Pull message delivery

The PubSub service also supports pull-style message delivery. Use the /topics/{topicOwnerClient}/{eventType}/read endpoint to read events from a topic. Then, use the /topics/{topicOwnerClient}/{eventType}/commit endpoint to acknowledge that the events have been processed.

Obtain the access token on behalf of the parent tenant of the consumer client. This addresses multi-tenancy in the PubSub service. Essentially, the PubSub service returns the events that belong to all tenants that are subscribed to your service, regardless of the specific tenant encoded in the access token. For more information, see the Security section.

After a successful read, the PubSub service temporarily locks the topic for the reading client. While a topic is locked, this same client cannot read any more events from the topic until the events have been committed, or the time-to-live of the lock expires (see below).

Customize read behavior

The PubSub service allows you to customize the event read behavior with three optional parameters that are passed as a JSON object in the body of the read request.

ParameterDescriptionDefault Value
numEventsThe maximum number of events returned in a given read request.1
ttlMSThe time-to-live in milliseconds of the lock on the topic after a successful read request.300000 (5 minutes)
autocommitIf events should be automatically committed.false. Autocommit is turned off by default.

This is an example request for reading a single event:

curl -X POST \
     -H "Authorization: Bearer access_token" \
     -H "Content-Type: application/json" \
     -d '{ \
           "numEvents": 1, \
           "ttlMs": 300000, \
           "autoCommit":true \
         }' \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/myEventType/read

Number of events to read

The numEvents parameter specifies the maximum number of events that are returned in a given read request. Note that you may get less events if there are not as many events in the topic, or if the total size of the events returned exceeds the specified limit.

Processing time

The ttlMs parameter lets you define how much time you expect it takes to process and commit the consumed events. The PubSub service locks the topic for this amount of time until you can send the next read request.

There are some trade-offs to consider when determining the ttlMS option:

ProblemDescription
Event redeliveryIf you set the time-to-live too short and fail to commit an event within the required period, the event may be redelivered.
Longer topic lockingIf you set the time-to-live too long and fail to commit an event, the topic stays locked for the specified amount of time until you can send the next read request.

Autocommit

If autocommit is set to true, any events read from a topic are automatically committed by the PubSub service, even before they are sent back in the response.

Be aware that you might lose events with autocommit because the response can never reach you, for example, due to network problems. In this case, the events have already been committed by the PubSub service. This means that they are effectively lost and won't be redelivered on the next read request.

Read response

Depending on the numEvents parameter, the response to the read request contains one or more events. In addition to the payload and metadata specified when the event was published, each event also includes the following metadata:

  • eventId - A pseudo random ID of the event, generated by the PubSub service. This can be used for deduplication support.
  • createdAt - A UNIX timestamp of when the PubSub service received the event.
  • sourceClient - The name of the YaaS client that published the event.
  • eventType - The type of the event. This is determined by the event type of the topic.
  • tenant - The tenant on whose behalf the event was published.

The response also contains a single token of type 'string' that must be sent back to the PubSub service when committing the events.

This shows an example response:

{
  "events": [
    {
      "id": "067e6162-3b6f-4ae2-a171-2470b63dff00",
      "createdAt": 1078884319047,
      "sourceClient": "hybris.order",
      "eventType": "order-created",
      "tenant": "myShop",
      "payload": "{ \"orderId\": \"123\" }"
    }
  ],
  "token": "ae6d8822-5712-481a-a252-65ad463f5af6"
}
Handle empty responses

The PubSub service may return an empty response, indicated by the 204 status code. Due to the way the PubSub service implements multi-tenancy, there are two possible causes for this:

  • The topic is empty. If this is the case, you should implement a back-off strategy. For example, you can use an exponential back-off strategy to slowly reduce the number of calls to the PubSub service.
  • Even though the read request returned an empty response, the topic may yet contain events for you to read. The PubSub service simply did not return them in order to provide predictable response times. If this is the case, you can immediately read again. To indicate that there may be more data available, the PubSub service includes a Link header in the empty response.

See here to learn more about multi-tenancy in PubSub.

Commit events

To guarantee message delivery, the PubSub service requires that the events are committed explicitly to indicate that they have been processed. If they are not committed within the specified time-to-live period, the service will redeliver them with the next request. The response to a read request contains a token of type 'string' that is required to commit the events.

The following example shows how to commit events:

curl -X POST \
     -H "Authorization: Bearer access_token" \
     -H "Content-Type: application/json" \
     -d '{ "token": "ae6d8822-5712-481a-a252-65ad463f5af6" }' \
     https://api.beta.yaas.io/hybris/pubsub/v1/topics/topicOwnerClient/anEventType/commit


Push vs. Pull Delivery

Comparison between Push and Pull

PushPull
Consuming eventsThe PubSub service pushes single events to an arbitrary HTTPS endpoint, secured with Basic Authentication.You pull events from a topic, either individually or in batches of multiple events.
LatencyEvents are delivered as soon as they become available.There's a delay between publishing an event and consuming it.
Event flowThe PubSub service dynamically adjusts the sending rate of events based on the number of successful and non-successful delivery attempts over a period of time. You implicitly acknowledge or decline an event by responding with HTTP 2xx or 4xx/5xx status codes, respectively.You pull events on demand from topics, and explicitly acknowledge that you processed them (assuming that you don't use autocommit). You can dynamically adjust the processing time (ttlMs). This gives you more control in general, but also increases the complexity on your side.
Retry PolicyThe PubSub service resends events for up to 48 hours if the subscription endpoint returns a non-successful HTTP status code (4xx/5xx) or doesn't respond within 5 seconds.PubSub keeps events that are not committed for up to 48 hours. You can retry a read request after the time-to-live of the topic lock has expired.

Recommendations when to use Push or Pull

Push

  • If you need performance closer to real-time.
  • If you prefer a less complex solution to the pull approach.

Pull

  • If your security policies forbid incoming network traffic.
  • If you need events only on demand, for example, if you want to control the rate at which you receive them.
  • If you need more control over the commit deadline.


Security

Manage topics

The YaaS client that creates a topic is considered the owner of the topic. Only the owner is allowed to delete a topic.

Publish to topics

Only the owner of a topic is allowed to publish events to it.

Consume from topics

Any YaaS client can access or subscribe to every topic in the PubSub service. However, this does not imply that you can read or receive events from any topic. This is governed by the rules of multi-tenancy. Topics support publishing and consuming events on behalf of multiple tenants. Tenants alone grant readers access to their data. In YaaS, a tenant is a Project. Consider these two cases:

  • Each YaaS client resides in a project. A client can always read events that belong to its parent tenant.
  • YaaS services are multi-tenant if tenants (projects) subscribe to their packages on the YaaS market. In this case, you receive all events that belong to the subscribed tenants.
For more information about multi-tenancy in YaaS, see the Key Concepts in YaaS document.

The following diagram presents at a high level how reading from topics works in a multi-tenant environment:

High-level overview of event data access control in the PubSub service

Tenant A subscribes to the package that contains the publisher client/service. Only then is the publisher allowed to publish events on behalf of Tenant A. To do so, the publisher requests a token from the OAuth service by providing its client ID, client secret, and the name of the tenant.

Initially, a consumer can only read events that belong to its own tenant, the Consumer Tenant. Only tenants give consumers the right to read their data. In the example, Tenant A needs to subscribe to the package that contains the consumer service to grant the consumer access to its data. Before issuing the request, the consumer must obtain a token from the OAuth2 service and include its client ID, client secret and the name of a tenant in the request. SAP Hybris recommends that the token is requested on behalf of the services's own tenant (Consumer Tenant). This addresses the multi-tenancy in the PubSub service. Essentially, the PubSub service returns the events that belong to all tenants that are subscribed to your service, regardless of the specific tenant encoded in the access token.

Verify that the consumer can access the tenant data

If a consumer cannot consume the tenant data, the consumer might not be allowed to see the it. As a quick check, the consumer can request an access token with the scope hybris.tenant=tenant-name. If the system issues the token successfully, the consumer can see the tenant data. Use one of the procedures that follow to perform this verification. In each procedure, use the same YaaS client used to consume the tenant data.

Use the Builder UI to verify consumer access

Follow these steps to generate an access token using the Builder UI:

  1. In the Builder, open the project that contains the client that consumes events from PubSub.
  2. Navigate to Development > Clients, and select the appropriate client.
  3. Click GENERATE ACCESS TOKEN.
  4. In the Access Token Generator, enter the name of the tenant in the Related Project ID field. For example, TenantA.
  5. Select the appropriate region from the Related Region list.
  6. Leave the Select Scopes list under Requested Scopes section empty.
  7. Click GENERATE.

If the system issues a token successfully, the Builder displays a dialog with the generated access token. This means that the consumer is allowed to see the tenant's data.

If the system does not allow the consumer to see the tenant data, the Builder shows an error message like:

Error while obtaining access token: Lack of subscription: tenant 'TenantA' is not subscribed to any package which contains application with client id: 'clientId'

Use the OAuth APIs to verify consumer access

This example demonstrates a sample HTTP request:

curl -X POST 'https://api.beta.yaas.io/hybris/oauth2/v1/token' \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d 'grant_type=client_credentials&client_id=clientId&client_secret=secret&scope=hybris.tenant=TenantA'

If the system allows the consumer to see the tenant data, the system gives this response:

{
  "token_type": "Bearer",
  "access_token": "xxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "expires_in": 3600,
  "scope": "hybris.tenant=TenantA"
}

If the system does not allow the consumer to see the tenant data, the system returns the following response with an HTTP response code of 400:

{
  "error": "invalid_scope",
  "error_description": "Lack of subscription: tenant 'TenantA' is not subscribed to any package which contains application with client id: 'clientId'.",
  "error_uri": "https://pattern.yaas.io/errortypes.html"
}


Considerations

Event ordering guarantees

The PubSub service does not guarantee that events are read/delivered in the same order that they are published. You need to handle the situations when events arrive in a random order. If the order matters, the event publisher and consumer should agree on how to establish the ordering. One way to address this, is to include the ordering information in the event itself.

Event delivery guarantees

PubSub provides at-least-once delivery. PubSub will deliver any event, that was successfully published, at least once to any active consumer. For pull delivery, this applies only if you don't use autocommit, and if you poll the events within the maximum lifetime of events in PubSub.

The PubSub service provides at-least-once delivery. This means that the service delivers any event that was successfully published at least once to any active consumer. For pull delivery, this applies only if you don't use autocommit, and if you read the events within the maximum lifetime of the events.

It is possible that you receive events more than once. For example, the topic lock may expire before the events have been processed and committed. You need to handle multiple deliveries of the same event.

Event loss scenarios

Events can be lost for several reasons:

  • The PubSub service persists successfully published events for 48 hours. After that time they are deleted.
  • When you commit an event, you will not be able to get it again using the same YaaS client.
  • The PubSub service skips the events in a topic for which you don't have the necessary permissions to read the data. They won't be redelivered even if these permissions change later.


Create, Delete and List Topics

This tutorial demonstrates how to manage your topics in the PubSub service.

  1. Get an access token.
  2. Create some topics.
  3. List those topics.
  4. Delete the topics.

Let's begin!

Step 1: Get an access token

Replace the topic owner data below with your own

ownerAppId = appIdPlaceholder
ownerClientId = clientIdPlaceholder
ownerClientSecret = clientSecretPlaceholder

Get an access token for a topic owner

API.createClient('oAuth2Service',
'/services/oauth2/v1/api.raml')
AccessToken = oAuth2Service.token.post({
'client_id' : ownerClientId,
'client_secret': ownerClientSecret,
'grant_type' : 'client_credentials',
'token_type': 'Bearer'
})

Make sure that you acquired the token:

chai.assert.equal(AccessToken.status, 200)
chai.expect(AccessToken.body.access_token).to.exist

owner_access_token = AccessToken.body.access_token

Step 2: Create two new topics

Create the Pubsub service client

Create an API client to interact with the PubSub service. Use the following script:

API.createClient('pubsub',
'/services/pubsub/v1/api.raml')

Send two POST requests to create the topics

Now you need to set the topic names:

topic1='listableTopic1'
topic2='listableTopic2'
//topic1
CreateTopicResponse = pubsub.topics.post({
  'eventType': topic1
}, {
headers: {
 'Authorization': 'Bearer ' + owner_access_token,
 'Content-type' : 'application/json'}})

You can check the response to make sure that the topic is created.

chai.assert.equal(CreateTopicResponse.status, 201)
CreateTopicResponse

Now create the second topic.

//topic2
CreateTopicResponse = pubsub.topics.post({
  'eventType': topic2
}, {
headers: {
 'Authorization': 'Bearer ' + owner_access_token,
 'Content-type' : 'application/json'}})

chai.assert.equal(CreateTopicResponse.status, 201)
CreateTopicResponse

After creating these topics, you should be able to list them.

Step 3: List your topics

Use the PubSub service API client that you created in the previous steps to fetch your topics.

Send the GET request to list the topics

TopicsResponse = pubsub.topics.topicOwnerClient(ownerAppId).get({}, {
headers: {
 'Authorization': 'Bearer ' + owner_access_token,
 'Content-type' : 'application/json'}})

Please verify that the topics are listed as expected.

chai.assert.equal(TopicsResponse.status, 200)
TopicsResponse

At this point, you have seen how to create topics and how to list them. Next, you will learn how to delete these topics.

Step 4: Delete the topics

Only the topic owner can delete this topic. Use the same PubSub service API client and send a DELETE request.

Send the DELETE request

DeleteResponse1 = pubsub.topics.topicOwnerClient(ownerAppId).eventType(topic1).delete({},{
headers: {
 'Authorization': 'Bearer ' + owner_access_token,
 'Content-type' : 'application/json'}})

DeleteResponse2 = pubsub.topics.topicOwnerClient(ownerAppId).eventType(topic2).delete({},{
headers: {
 'Authorization': 'Bearer ' + owner_access_token,
 'Content-type' : 'application/json'}})

DeleteResponse1

Verify that everything went as expected.

chai.assert.equal(DeleteResponse1.status, 202)
chai.assert.equal(DeleteResponse2.status, 202)
DeleteResponse2

To double-check that both topics are deleted, you can try to list them again.

List the topics again

TopicsResponse = pubsub.topics.topicOwnerClient(ownerAppId).get({}, {
headers: {
 'Authorization': 'Bearer ' + owner_access_token,
 'Content-type' : 'application/json'}});

Have fun with the PubSub service!


Publish and Consume an Event

Overview

The purpose of this tutorial is to describe how to publish, consume, and commit events using the PubSub service.

In this tutorial, you will integrate different components of a sample Customer service to reset a password. One component receives and validates the password reset request, and another component does the actual processing. These components share the same Builder credentials.

A customer password reset request typically originates from a user interface. The Customer service receives and validates the request. If everything is correct, it sends a password-reset-requested event and then sends an acknowledgment back to the user interface that the request has been accepted. Another component of the Customer service consumes the password-reset-requested event and performs the actual processing.

Occasionally, processes might be slow or might fail and must be retried. By handling the processes in this manner, the Customer service can be more responsive to user interfaces and more resilient and scalable when it comes to processing the events.

Steps

In this scenario, the consumer service completes the following actions:

  • Publishes a password-reset-requested event
  • Consumes the event
  • Commits the event

A prerequisite is to set up the topic and obtain an access token as shown in this tutorial.

Step 1: Set up the password-reset-requested topic

First, inject your credentials:

ownerAppId = {{clientName}};
ownerClientId = {{clientId}};
ownerClientSecret = {{clientSecret}};

Next, get an OAuth2 access token:

API.createClient('oAuth2Service',
'/services/oauth2/v1/api.raml')

Now retrieve the access token:

AccessToken = oAuth2Service.token.post({
'client_id' : ownerClientId,
'client_secret': ownerClientSecret,
'grant_type' : 'client_credentials',
'token_type': 'Bearer'})

When the access token is successfully issued, the service returns a 200 status code.

chai.assert.equal(AccessToken.status, 200)
owner_access_token = AccessToken.body.access_token

And create an API client for the PubSub service:

API.createClient('pubsub',
'/services/pubsub/v1/api.raml')

Create a new topic through PubSub called password-reset-requested.

topic='password-reset-requested'

CreateTopicResponse = pubsub.topics.post({
  'eventType': topic
}, {
headers: {
 'Authorization': 'Bearer ' + owner_access_token,
 'Content-type' : 'application/json'}})

Step 2: The Customer service sends the password-reset-requested event

The Customer service sends the password-reset-requested event:

event_payload = "{ \"email\": \"someCustomerEmailAddress@someDomain.com\" }"
PublishResponse = pubsub.topics.topicOwnerClient(ownerAppId).eventType(topic).publish.post(
  { "payload" : event_payload },
  { headers: {
  'Authorization': 'Bearer ' + owner_access_token,
  'Content-type' : 'application/json'}})

The response code must be 201, indicating that the event is published:

chai.assert.equal(PublishResponse.status, 201)
PublishResponse.status

Step 3: The Customer service consumes the event

Typically, you want to control when to commit an event. In other cases, when delivery guarantee is not mandatory, you can enable autocommit when sending a read request.

If you want to test the autocommit feature, change the snippet below to autocommit = true.

autocommit = false

Now the Customer service is ready to consume one password reset event:

retries = 0
do {
  retries = retries + 1;
  ReadResponse = pubsub.topics.topicOwnerClient(ownerAppId).eventType(topic).read.post(
    { "numEvents": 1, "ttlMs": 300000, "autocommit": autocommit},
    { headers: {
    'Authorization': 'Bearer ' + owner_access_token,
    'Content-type' : 'application/json'}})
} while (ReadResponse.status == 204 && retries < 5)
The code snippet above lists the retry attempts as five to give the PubSub service adequate time to process the event and serve it to the consumer. In a real-world scenario, allow more time before attempting to read again.

The numEvents field allows you to consume more than one event at once.

Ensure that the response code is 200, indicating that the event read successfully

chai.assert.equal(ReadResponse.status, 200)
ReadResponse.status

Ensure that the email address matches the one from the request, as shown in the following example:

chai.assert.equal(ReadResponse.body.events[0].payload, event_payload)
ReadResponse.body.events[0].payload

If you did not use the autocommit function, you must process and commit the event.

Step 4: The Customer service commits the event

Assuming that the Customer service has correctly processed the password-reset-requested event, it can now commit the event:

if (!autocommit) {
  CommitResponse = pubsub.topics.topicOwnerClient(ownerAppId).eventType(topic).commit.post(
    {  "token": ReadResponse.body.token },
    { headers: {
    'Authorization': 'Bearer ' + owner_access_token,
    'Content-type' : 'application/json'}})
}

Verify that the response code is 200:

if (!autocommit) {
  chai.assert.equal(CommitResponse.status, 200)
  CommitResponse.status
}

Step 5: Delete the topic

As this is a test topic, you can safely delete the topic:

topic='password-reset-requested'
DeleteResponse1 = pubsub.topics.topicOwnerClient(ownerAppId).eventType(topic).delete({},{
headers: {
 'Authorization': 'Bearer ' + owner_access_token,
 'Content-type' : 'application/json'}})


Security

Manage topics

The YaaS client that creates a topic is considered the owner of the topic. Only the owner is allowed to delete a topic.

Publish to topics

Only the owner of a topic is allowed to publish events to it.

Consume from topics

Any YaaS client can access or subscribe to every topic in the PubSub service. However, this does not imply that you can read or receive events from any topic. This is governed by the rules of multi-tenancy. Topics support publishing and consuming events on behalf of multiple tenants. Tenants alone grant readers access to their data. In YaaS, a tenant is a Project. Consider these two cases:

  • Each YaaS client resides in a project. A client can always read events that belong to its parent tenant.
  • YaaS services are multi-tenant if tenants (projects) subscribe to their packages on the YaaS market. In this case, you receive all events that belong to the subscribed tenants.
For more information about multi-tenancy in YaaS, see the Key Concepts in YaaS document.

The following diagram presents at a high level how reading from topics works in a multi-tenant environment:

High-level overview of event data access control in the PubSub service

Tenant A subscribes to the package that contains the publisher client/service. Only then is the publisher allowed to publish events on behalf of Tenant A. To do so, the publisher requests a token from the OAuth service by providing its client ID, client secret, and the name of the tenant.

Initially, a consumer can only read events that belong to its own tenant, the Consumer Tenant. Only tenants give consumers the right to read their data. In the example, Tenant A needs to subscribe to the package that contains the consumer service to grant the consumer access to its data. Before issuing the request, the consumer must obtain a token from the OAuth2 service and include its client ID, client secret and the name of a tenant in the request. SAP Hybris recommends that the token is requested on behalf of the services's own tenant (Consumer Tenant). This addresses the multi-tenancy in the PubSub service. Essentially, the PubSub service returns the events that belong to all tenants that are subscribed to your service, regardless of the specific tenant encoded in the access token.

Verify that the consumer can access the tenant data

If a consumer cannot consume the tenant data, the consumer might not be allowed to see the it. As a quick check, the consumer can request an access token with the scope hybris.tenant=tenant-name. If the system issues the token successfully, the consumer can see the tenant data. Use one of the procedures that follow to perform this verification. In each procedure, use the same YaaS client used to consume the tenant data.

Use the Builder UI to verify consumer access

Follow these steps to generate an access token using the Builder UI:

  1. In the Builder, open the project that contains the client that consumes events from PubSub.
  2. Navigate to Development > Clients, and select the appropriate client.
  3. Click GENERATE ACCESS TOKEN.
  4. In the Access Token Generator, enter the name of the tenant in the Related Project ID field. For example, TenantA.
  5. Select the appropriate region from the Related Region list.
  6. Leave the Select Scopes list under Requested Scopes section empty.
  7. Click GENERATE.

If the system issues a token successfully, the Builder displays a dialog with the generated access token. This means that the consumer is allowed to see the tenant's data.

If the system does not allow the consumer to see the tenant data, the Builder shows an error message like:

Error while obtaining access token: Lack of subscription: tenant 'TenantA' is not subscribed to any package which contains application with client id: 'clientId'

Use the OAuth APIs to verify consumer access

This example demonstrates a sample HTTP request:

curl -X POST 'https://api.beta.yaas.io/hybris/oauth2/v1/token' \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d 'grant_type=client_credentials&client_id=clientId&client_secret=secret&scope=hybris.tenant=TenantA'

If the system allows the consumer to see the tenant data, the system gives this response:

{
  "token_type": "Bearer",
  "access_token": "xxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "expires_in": 3600,
  "scope": "hybris.tenant=TenantA"
}

If the system does not allow the consumer to see the tenant data, the system returns the following response with an HTTP response code of 400:

{
  "error": "invalid_scope",
  "error_description": "Lack of subscription: tenant 'TenantA' is not subscribed to any package which contains application with client id: 'clientId'.",
  "error_uri": "https://pattern.yaas.io/errortypes.html"
}


Glossary

TermDescription
eventA message that contains information about something that occurred.
subscriberIn this document specifically, this is limited to subscribing to topics.
topicAn identifiable destination (URL) where events can be published, subscribed to, and consumed.


  • Send feedback

    If you find any information that is unclear or incorrect, please let us know so that we can improve the Dev Portal content.

  • Get Help

    Use our private help channel. Receive updates over email and contact our specialists directly.

  • hybris Experts

    If you need more information about this topic, visit hybris Experts to post your own question and interact with our community and experts.