Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

March Developer Challenge - CloudEvents: Week 3

ajmaradiaga
Developer Advocate
Developer Advocate

Last week we learnt how to create CloudEvents programmatically by using one of the many SDKs available. This week we will extend the CloudEvent created last week and we will send it to SAP Integration Suite, advanced event mesh.

Week 3 dev challenge data flowWeek 3 dev challenge data flow

Before we get to the challenge, we might need to talk a bit about what an Event-Driven architecture is and why it is so important. Let's get started.

Links to March's developer challenge:

Event-Driven Architectures

Long gone are the days when a system (aka target system) will constantly poll to check if there are any changes in another system, e.g. a new customer created in a master data system. Traditionally, the target system will only know this by programming a routine that will poll a service exposed in the source system every X minutes/hours/days. The expectation nowadays is that systems are integrated and that the data exchanged between these systems will be immediately available in the target system(s) if any data is created/changed in the source system. Enter Event-Driven architectures.

An Event-Driven Architecture is a software architecture paradigm concerning the production and consumption of events. An event can be defined as a significant change in the state of an object within a system[1]. For example, when a customer/supplier/employee (business object) is created/updated/deleted (action) in a system. Translating this to the SAP world, when a Business Partner is created/changed in SAP S/4HANA (source system), SAP S/4HANA can notify that there was a change in a business object and target system(s) interested in the Business Partner object can then react (do something about it) if they need to. This could be create/update/delete the object in their systems.

How do source and target systems communicate?

Now, if the source system lets other systems know of any changes happening in its business objects, it will not be sustainable to create a new programming routine within the source system every time we want to notify a new target system of any changes. Traditionally we would have some form of middleware, e.g. SAP Cloud Integration, and configure our source system, an SAP S/4HANA system, to send notifications of these events to the middleware and then use the middleware to distribute these messages, e.g. we would add target system(s) as needed. Now, we are moving the problem from the source system to a sort of middleware but ideally, there will be a way for the source system to notify others without the need to make any changes. Enter the event broker.

An event broker is message-oriented middleware that enables the transmission of events between different components of a system, acting as a mediator between publishers and subscribers. It is the cornerstone of event-driven architecture, and all event-driven applications use some form of event broker to send and receive information[2].

By introducing an event broker in our landscapes, we can configure our source systems to publish their events to this message-oriented middleware. The source system will specify the class of the message (aka topic). Then, systems interested in the changes happening, in a particular business object, in the source system can subscribe to the event(s), via the event broker, by specifying the topic they are interested in. There are two keywords important here, publish and subscribe (PubSub), this is a well-known messaging pattern used to decouple systems/applications and allow communication between them.

What is the PubSub messaging pattern?

Publish-subscribe is a communication pattern that is defined by the decoupling of applications, where applications publish messages to an intermediary broker rather than communicating directly with consumers (as in point-to-point)[3]. In a way, publishers and consumers do not need to know each other; they simply publish (produce) or consume (receive) the events. When following this messaging pattern we move from, the traditional polling mechanism to know if there have been any changes in the source system, to reacting to real-time events (notifications) the moment something happens in the source system.

CloudEvents-PubSub.drawio.png

 

We mentioned before how target systems can subscribe to events by specifying a topic they are interested in.... some event brokers will allow subscribers to subscribe to topics by using wildcards (*) and they will be able to receive messages for different topics. For example, let's assume we have an SAP S/4HANA with the name S4D and it publishes the Business Partner create and change on the following topics: sap/S4HANAOD/S4D/ce/sap/s4/beh/businesspartner/v1/BusinessPartner/Created/v1 and sap/S4HANAOD/S4D/ce/sap/s4/beh/businesspartner/v1/BusinessPartner/Changed/v1. A subscriber system could subscribe to both topics using a wildcard, e.g. sap/S4HANAOD/S4D/ce/sap/s4/beh/businesspartner/v1/BusinessPartner/*/v1 and receive the message for both event types.

With many systems in our landscapes and each one being developed by different vendors/teams, it would be good if there was a standard way of structuring these events to simplify how systems create/handle/process these messages right? This is why we first learnt about CloudEvents 😃.

Now, we can use the CloudEvents message format to exchange messages between systems/services/applications. In our case, we will publish a CloudEvent to a topic in one of SAP's event-driven portfolio products: SAP Integration Suite, advanced event mesh.

SAP Integration Suite, advanced event mesh

CloudEvents-EDA.drawio.png

 

SAP offers various services that can help customers embrace event-driven architectures. The different offerings can meet customers where they are in their EDA adoption/implementation journey. These are:

  • SAP Event Broker for SAP cloud applications
  • SAP Event Mesh
  • SAP Integration Suite, advanced event mesh

Now, for this week's challenge we will focus on communicating SAP Integration Suite, advanced event mesh (AEM), which is a complete event streaming, event management, and monitoring platform that incorporates best practices, expertise, and technology for event-driven architecture (EDA) on a single platform. With AEM you can deploy event broker services, create event meshes, and optimize and monitor your event-driven system.

📢To learn more about SAP's event-driven portfolio check out this blog post: CloudEvents at SAP 🌁 https://community.sap.com/t5/application-development-blog-posts/cloudevents-at-sap/ba-p/13620137.

Connecting with SAP Integration Suite, advanced event mesh (AEM)

We can use different protocols to connect with AEM, this will depend on our needs and the type of service/device that will be publishing/consuming messages. The event broker provides a foundation for multi-protocol and standards eventing including Solace Message Format (SMF), JMS1.1, MQTT3.11, REST, and AMQP1.0[1].

Protocols supportedProtocols supported


Also, there are many connectivity options available depending on your favourite programming language.

Check out the tutorials available for the different programming languages - https://tutorials.solace.dev/.

wk3-languages.png

To keep things simple for this developer challenge, we are going to use the REST Messaging Protocol[3] to send messages (publish) to the event broker by using HTTP POST requests. This uses standard HTTP, which we are all familiar with, meaning that you can send messages with any REST client, e.g. Bruno.

In our case, we are interested in producing messages so we will act as a REST producer and send messages to a topic in the event broker. A REST message sent from a publisher to an event broker consists of a POST request, HTTP headers, and an HTTP message body. The event broker uses the POST request to determine where to route the message, and the HTTP headers specify message properties that may determine how the message is handled. The body of the POST request is included as the message payload.

When an event broker successfully receives a REST message, it sends back an acknowledgement (“ack”) in the form of a POST response. An ack consists of a response code (typically 200 OK) and HTTP headers. Because the response code is sufficient to acknowledge receipt of the original message, the returned message has an empty message body.

We can also use the REST Messaging APIs to consume messages but this requires some additional configuration in the event broker, e.g. setting up a REST Delivery Point, aka Webhook.

We can send messages to a topic or a queue. Below are some examples of how we can send a message to a topic or a queue[2]:

  • Sending a message to a topic "a" (both commands are equivalent):

    curl -X POST -d "Hello World Topic" http://<host:port>/a --header "Content-Type: text/plain"
    curl -X POST -d "Hello World Topic" http://<host:port>/TOPIC/a --header "Content-Type: text/plain"
    
  • Sending a message to a queue "Q/test":

    curl -X POST -d "Hello World Queue" http://<host:port>/QUEUE/Q/test --header "Content-Type: text/plain"
    

You'll notice that in the examples above we are sending as the body of our message plain text. When sending a CloudEvent the Content-Type would be 'application/cloudevents+json'

 
🔍Interested in knowing what Sending a CloudEvent to a topic looks like using curl?

wk3-curl-cloudevent-sample.png

As part of this week's challenge we will POST our CloudEvent to a topic. In our case, the topic will be /dev-challenge/week-3/{{sapcommunityid}}/ce and this is how we include it in the POST request URL: https://{{host}}:{{port}}/TOPIC/dev-challenge/week-3/{{sapcommunityid}}/ce

Week 3 challenge - Send CloudEvent to SAP Integration Suite, advanced event mesh

Week 3 dev challenge data flowWeek 3 dev challenge data flow

👉 Your task for this week is: Extend the CloudEvent you created for last week's challenge and add an extension context attribute (sapcommunityid). You will need to specify your sapcommunityid, e.g. ajmaradiaga in my case, as a value here. Please ensure that you specify the sapcommunityid in the message, if not it will not count as valid. Note: The diagram above captures the data flow of this week's challenge.

Once you've extended the original message, send the message to SAP Integration Suite, advanced event mesh - by publishing the message in the topic dev-challenge/week-3/[my-sap-community-id]/ce. In the comments, share a snippet of your code where the connectivity is taking place and post a screenshot of the successful run of your code. Use the credentials below to connect to AEM. Note: You can check that your message was received and consumed on this website: https://ce-dev-challenge-wk3.cfapps.eu10.hana.ondemand.com/consumed-messages/webapp/index.html.

For example, in my case I will publish the message to the topic dev-challenge/week-3/ajmaradiaga/ce

Bonus:

You can also try sending the CloudEvent message using a protocol different than REST, e.g. AMQP, SMF. There is no need to reinvent the wheel here... check out the code available in the Solace Samples org, e.g. for Node.js, Python and the tutorials available for the different programming languages. There are plenty of examples there that show you how to use the different protocols.


🚨Credentials 🚨

To communicate with AEM, you will need to authenticate when posting a message. In the section below you can find the credentials required to connect.

For the adventurous out there.... I'm also sharing the connection details for different protocols that we can use to communicate with AEM, e.g. AMQP, Solace Messaging, Solace Web Messaging. In case you want to play around and get familiar with different protocols.

🔐Expand to view credential details 🔓

Spoiler
  • Connection Type:
    REST: https://mr-connection-plh11u5eu6a.messaging.solace.cloud:9443
    AMQP: amqps://mr-connection-plh11u5eu6a.messaging.solace.cloud:5671
    Solace Messaging: tcps://mr-connection-plh11u5eu6a.messaging.solace.cloud:55443
    Solace Web Messaging: wss://mr-connection-plh11u5eu6a.messaging.solace.cloud:443
  • Username: solace-cloud-client
  • Password: mcrtp5mps5q12lfqed5kfndbi2
  • Message VPN: eu-fr-devbroker

Validation process for this week's challenge

As part of the validation process for this week's challenge, there is a consumer service (Monitoring service in the diagram above) that will process the messages sent. The consumer program will validate that the message you post includes an extension context attribute (sapcommunityid) and this will need to match the path specified for the topic. As for previous weeks, I will kudo a successful response and I will post every day the SAP Community IDs of the messages received and processed successfully.

You can monitor the messages processed by the consumer service on this website: https://ce-dev-challenge-wk3.cfapps.eu10.hana.ondemand.com/consumed-messages/webapp/index.html. If there is an error in the message sent, the monitoring app will tell you what the error is, e.g. not a valid CloudEvent, sapcommunityid extension context attribute missing, or sapcommunityid doesn't match community Id specified in topic. The consumer service is subscribed to the topics using a wildcard - dev-challenge/week-3/*/ce. Meaning that it will only process messages sent to topics that fit that pattern.

Below you can see a screenshot of a message processed successfully by the consumer service.

wk3-screenshot-monitoring.pngExample of a payload containing the extension context attribute sapcommunityid:

 

 

 

 

 

{
    "specversion": "1.0",
    "id": "204f70c0-1301-4812-9705-8db7ab57065e",
    "source": "https://tms-prod.ajmaradiaga.com/tickets",
    "type": "com.ajmaradiaga.tms.Ticket.Created.v1",
    "time": "2024-03-17T12:34:03.180643+00:00",
    "data": {
        "id": "IT00010232",
        "description": "Install ColdTurkey to block distracting websites.",
        "urgency": {
            "id": 1,
            "description": "High"
        }
    },
    "sapcommunityid": "ajmaradiaga"
}​

 

 

 

 

 

  1. How Apps Interact with PubSub+ Messaging Components: link ↩︎ 

  2. Solace REST Example Code: link ↩︎  

  3. REST Messaging Protocol: link ↩︎ 

31 REPLIES 31

ajmaradiaga
Developer Advocate
Developer Advocate
0 Kudos

Sample Solution

Using REST:

 

print("===========\nCloud Event\n===========\n")

print(f"Headers: {headers}")

json_body = json.loads(body)

# Pretty print json
print(f"Message: {json.dumps(json_body, indent=2)}")

topic = f"dev-challenge/week-3/{SAP_COMMUNITY_ID}/ce"
print(f"\nSending message to topic: {topic}")

response = requests.post(
    f"{SOLACE_TRANSPORT_PROTOCOL}://{SOLACE_HOST}:{SOLACE_PORT}/TOPIC/{topic}", data=body, headers=headers,
    auth=HTTPBasicAuth(SOLACE_USERNAME, SOLACE_PASSWORD))

print(f"\n=============\nHTTP Response\n=============\nStatus code: {response.status_code}")

 

Screenshot:

Screenshot solutionScreenshot solution

 

0 Kudos

An alternative would be using Solace Messaging:

# Import Solace Python  API modules
from solace.messaging.messaging_service import MessagingService, ReconnectionListener, ReconnectionAttemptListener, ServiceInterruptionListener, RetryStrategy, ServiceEvent
from solace.messaging.errors.pubsubplus_client_error import PubSubPlusClientError
from solace.messaging.publisher.direct_message_publisher import PublishFailureListener, FailedPublishEvent
from solace.messaging.resources.topic_subscription import TopicSubscription
from solace.messaging.receiver.message_receiver import MessageHandler
from solace.messaging.config.solace_properties.message_properties import APPLICATION_MESSAGE_ID
from solace.messaging.resources.topic import Topic
from solace.messaging.receiver.inbound_message import InboundMessage
from solace.messaging.config.transport_security_strategy import TLS

.....

message_builder = messaging_service.message_builder() \
                .with_property("language", "Python") \

try:
    while True:
        
        topic, json_str = random_cloud_event()
        additional_properties = {APPLICATION_MESSAGE_ID: f'sample_id 1'}
        # Creating a dynamic outbound message 
        outbound_message = message_builder.build(json_str, additional_message_properties=additional_properties)
        # Direct publish the message
        direct_publisher.publish(destination=Topic.of(topic), message=outbound_message)
        print("Sent")

        time.sleep(15)
        
except KeyboardInterrupt:
        print('\nDisconnecting Messaging Service')
finally:
    print('Terminating Publisher and Receiver')
    direct_publisher.terminate()
    print('Disconnecting Messaging Service')
    messaging_service.disconnect()

r00k13d3v
Participant

Here is my submission 👌

Code JS:

 

...
async function sendCloudEvent() {
    try {
        const response = await axios({
            method: "post",
            url: `${SOLACE_TRANSPORT_PROTOCOL}://${SOLACE_HOST}:${SOLACE_PORT}/TOPIC/dev-challenge/week-3/${SAP_COMMUNITY_ID}/ce`,
            data: body,
            headers: {
                ...headers,
                Authorization: `Basic ${Buffer.from(`${SOLACE_USERNAME}:${SOLACE_PASSWORD}`).toString("base64")}`,
            },
        });

        console.log("Response Status:", response.status);
    } catch (error) {
        console.error("Error:", error);
    }
}

sendCloudEvent();

 

  Result:

r00k13d3v_2-1710836080993.png

 

This example doesn't contain the sapcommunityid but I can see in the monitoring app that you've sent one containing the extension context attribute....

ajmaradiaga_0-1710836325302.png

 

PWS:

$cloudEventStructuredHttpMessage = $cloudEvent | ConvertTo-HttpMessage -ContentMode Structured

Write-Host "Headers:" -ForegroundColor Green
$cloudEventStructuredHttpMessage.Headers | Out-Host

Write-Host "Body:" -ForegroundColor Green
Read-CloudEventData -CloudEvent $cloudEvent | Out-Host

$uri = "${SOLACE_TRANSPORT_PROTOCOL}://${SOLACE_HOST}:${SOLACE_PORT}/TOPIC/${topic}"
$body = Read-CloudEventData -CloudEvent $cloudEvent

$headers = @{
    "Content-Type" = "application/cloudevents+json"
    "Authorization" = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($SOLACE_USERNAME):$($SOLACE_PASSWORD)"))
}

try {
    $webResponse = Invoke-WebRequest -Method Post -Uri $uri -Headers $headers -Body $body -ContentType "application/json"
    Write-Host "Response status code:" $webResponse.StatusCode
}
catch {
    Write-Host "Error: $($_.Exception.Response.StatusCode.Value__) $($_.Exception.Message)"
}

Result:

r00k13d3v_0-1711054104420.pngr00k13d3v_1-1711054139278.png

pamoli_banerjee
Explorer

Hello , here is my response 

Code in node.js : 

pamoli_banerjee_0-1710846960137.png

Response : 

pamoli_banerjee_1-1710847011443.png

And here is my valid entry in the app : 

pamoli_banerjee_2-1710847059612.png

 

 

spirit2681
Explorer

Here is my nodejs code:

const { CloudEvent, HTTP } = require("cloudevents");
const axios = require('axios');
const dotenv = require('dotenv');

const ce = new CloudEvent({
  "specversion": "1.0",
  "type": "com.sonal.plm.NPDI.Created.v1",
  "source": "https://plm-prod.sonal.com/npdis",
  "subject": "NPDI000000001",
  "id": "196179a2-6cf1-4166-9975-51f9afdb3a0d",
  "time": "2024-03-06 12:00:00",
  "datacontenttype": "application/json",
  "data": { 
    "id": "NPDI000000001",
    "description": "New Product Development and Introduction Created"
  },
  "sapcommunityid":"spirit2681"
})
const { headers, body } = HTTP.structured(ce);

// Load the environment variables from the .env file
dotenv.config();

const {SOLACE_TRANSPORT_PROTOCOL, SOLACE_HOST, SOLACE_PORT, SOLACE_TOPIC, SAP_COMMUNITY_ID, SOLACE_USERNAME, SOLACE_PASSWORD} = process.env;

//Output
console.log(
   "Headers:", "\n",
    JSON.stringify(headers, null, 2), "\n",
    "Body:", "\n",
    JSON.stringify(JSON.parse(body), null, 2));

const eventSender = async () => {
    try {
        const response = await axios({
            method: "post",
            url: `${SOLACE_TRANSPORT_PROTOCOL}://${SOLACE_HOST}:${SOLACE_PORT}/TOPIC/${SOLACE_TOPIC}/${SAP_COMMUNITY_ID}/ce`,
            data: body,
            headers: {
                ...headers,
                Authorization: `Basic ${Buffer.from(`${SOLACE_USERNAME}:${SOLACE_PASSWORD}`).toString("base64")}`,
            },
        });
        console.log("Sending message to the topic: ", `${SOLACE_TOPIC}/${SAP_COMMUNITY_ID}`);
        console.log("Response Status:", response.status);
    } catch (error) {
        console.error("Error:", error);
    }
}

eventSender();

 Output:

spirit2681_0-1710853208150.png

And here is the valid entry in the app:

spirit2681_1-1710853293946.png

 

Dan_Wroblewski
Developer Advocate
Developer Advocate

Code with REST call:

Dan_Wroblewski_0-1710858942564.png

Code running:

Dan_Wroblewski_1-1710859063465.png

Message received:

Dan_Wroblewski_2-1710859149269.png

 

 




--------------
See all my blogs and connect with me on Twitter / LinkedIn

emiliocampo
Explorer

Code Python

event = CloudEvent(attributes, data)

# Creates the HTTP request representation of the CloudEvent in binary content mode
headers, body = to_binary(event)

# Pretty print header
print("Header \n{")
for key, value in headers.items():
    print(f'  "{key}":"{value}",')
print("}")

# Pretty print json body
json_body = json.loads(body)
print(f"Body \n{json.dumps(json_body, indent=2)}")

topic = f"dev-challenge/week-3/{SAP_COMMUNITY_ID}/ce"
print(f"\nSending message to topic: {topic}")

response = requests.post(
    f"{SOLACE_TRANSPORT_PROTOCOL}://{SOLACE_HOST}:{SOLACE_PORT}/TOPIC/{topic}", data=body, headers=headers,
    auth=HTTPBasicAuth(SOLACE_USERNAME, SOLACE_PASSWORD))

print(f"Status code {response.status_code}")

Result

emiliocampo_0-1710861025774.png

And here is the valid entry in the app:

emiliocampo_1-1710861131119.png

 

 

xavisanse
Active Participant
const { CloudEvent, HTTP } = require("cloudevents");
require('dotenv').config();

//cloud event data
const type = "com.awesome_company.sales_order.Updated.v1"
const source = "https://prod.illidian.awesome_company.com/sales_orders" 
const salesOrderID = "9024000013"
const company = "AWO01"
const year = 2024
const statusSO = "Shipped"

const subject = company + salesOrderID + year

const data = {
    "salesOrder": salesOrderID,
    "company": company,
    "year": year,
    "status": statusSO
}

const sapcommunityid = "xavisanse"
//creating event

const soEvent = new CloudEvent({type,source,subject,data,sapcommunityid})


//sending event to Solace
const solace_protocol = "https"
const solace_topic = `dev-challenge/week-3/${sapcommunityid}/ce`

const { headers, body } = HTTP.structured(soEvent);

const postURL = `${solace_protocol}://${process.env.SOLACE_HOST}:${process.env.SOLACE_PORT}/TOPIC/${solace_topic}`

// Basic Authentication
const basicAuth = 'Basic ' + Buffer.from(process.env.SOLACE_USER + ':' + process.env.SOLACE_PWD).toString('base64');

headers["Authorization"] = basicAuth;

console.log("### March Developer Challenge - CloudEvents: Week 3 ###\n");
console.log("- HTTP Request Event Headers - \n")
for (const key in headers) {
    console.log(`Key: "${key}", Value: "${headers[key]}"`);
  }

console.log("\n - HTTP Request Event Body - \n");
console.log(JSON.stringify(JSON.parse(body), null, 1) + "\n");
console.log("\n - HTTP Response - ")

// Sending POST request to Solace
fetch(postURL, {
    method: 'POST',
    headers: headers,
    body: body
})
.then(response => {
    // Check if the response is OK
    if (!response.ok) {
        throw new Error('Network response was not ok');
    }
    // Return a response with HTTP status and a message
    return {
        status: response.status,
        message: 'CloudEvent successfully sent to Solace.'
    };
})
.then(responseObj => {
    // Print the response
    console.log('Response:', responseObj);
})
.catch(error => {
    // Print error message
    console.error('There was a problem with the fetch operation:', error);
});

Screenshot of the call: 

xavisanse_0-1710877467070.png

url of the log: https://ce-dev-challenge-wk3.cfapps.eu10.hana.ondemand.com/consumed-messages/webapp/index.html#/mess...

 

 

ajos
Explorer

PriyankaChak
Active Contributor

Screenshot 2024-03-20 at 8.23.23 PM.png

Python Code:

from cloudevents.conversion import to_structured
from cloudevents.http import CloudEvent
import json
import requests
import os

SAP_COMMUNITY_ID = "PriyankaChak"
REST_URL = "https://mr-connection-plh11u5eu6a.messaging.solace.cloud:9443"
username = os.environ.get('SOLACE_USERNAME')
password = os.environ.get('SOLACE_PASSWORD')


attributes = {
    "type": "com.servicechannel.WorkOrder.Created.v1",
    "source": "https://test.servicechannel.com/workorders",
    "sapcommunityid": SAP_COMMUNITY_ID
}


data = {
        "purchaseNumber": "84409626",
        "status": {
            "primary": "open"
        }
    }

topic = f"dev-challenge/week-3/{SAP_COMMUNITY_ID}/ce"



event = CloudEvent(attributes, data)

headers, body = to_structured(event)
print(f"Content-Type: {headers['content-type']}\n")
json_body = json.loads(body)
print(f"Sample Cloud Event: \n{json.dumps(json_body, indent=2)}")

response = requests.post(url=f"{REST_URL}/TOPIC/{topic}", auth=(username,password), headers=headers,data=body)
print(f"Response Status code:{response.status_code}")

Screenshot 2024-03-20 at 8.29.34 PM.png 

fjaviergar07
Explorer

Hello,

Sending the event with HTTP 200 response:

2024-03-20 17_06_33-New Request - My Workspace.png

Validation in the app:

Fiori validation.png

BR
Javier

0 Kudos

Good one... you can indeed post a message with any REST client but I do have to warn you that some code will be needed for the challenge next week 🙂

MioYasutake
Active Contributor

JavaScript code:

const axios = require("axios").default;
const { HTTP, CloudEvent, httpTransport, emitterFor } = require("cloudevents");
const baseUrl = "https://mr-connection-plh11u5eu6a.messaging.solace.cloud:9443";
const sapcommunityid = "MioYasuatke"

const ce = new CloudEvent({
    type: "my.bank.account.balanceChange",
    source: "/my/bank/account",
    datacontenttype: "application/cloudevents+json",
    sapcommunityid: sapcommunityid,
    data: {
        "account": "12345678"
    }
});
console.log(ce);

try {
    axios({
        method: "post",
        url: baseUrl + `/TOPIC/dev-challenge/week-3/${sapcommunityid}/ce`,
        data: ce,
        headers: {
            "content-type": "application/cloudevents+json",
            "authorization": "Basic c29sYWNlLWNsb3VkLWNsaWVudDptY3J0cDVtcHM1cTEybGZxZWQ1a2ZuZGJpMg=="
        }
    }).then(response => {
        console.log(response.status);
    })    
} catch (error) {
    console.log("error!");
    console.log(error);
}

Results:

MioYasuatke_1-1710967464253.png

 

MioYasuatke_0-1710967403227.png

 

Alpesa1990
Explorer

Code in JS

 

//Send Message to IS event mesh
async function EventPost(){
  try {
    const response = await axios({
        method: "post",
        url: url,
        data: ce,
        headers: {
            Authorization: `Basic ${Buffer.from(`${user}:${pass}`).toString("base64")}`,
        },
    });
        console.log("Response:", response.status);
    } catch (error) {
        console.error("Error:", error);
}
};

EventPost();

Result:

Alpesa1990_0-1711025617710.png

Check

Alpesa1990_1-1711025791682.png

 

 

tobiasz_h
Active Participant

Hello,

Here is my solution:

tobiasz_h_0-1711098134041.pngtobiasz_h_1-1711098161277.pngtobiasz_h_2-1711098181814.png

 

geek
Participant
const response = await axios({
  method: "post",
  url: url + topic,
  headers: {
    //"Content-Type": "application/cloudevents+json",
    Authorization: `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`
  },
  data: ce,
});

console.log(
  "Response:", response.status);
} catch (error) {
  console.error("Error", error);
}
}
Send();

geek_0-1711132018342.png

geek_1-1711132172933.png

 

0 Kudos

Missed the top part:

const Send = async() => {
try{

const response = await axios({
  method: "post",
  url: url + topic,
  headers: {
    //"Content-Type": "application/cloudevents+json",
    Authorization: `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`
  },
  data: ce,
});

console.log(
  "Response:", response.status);
} catch (error) {
  console.error("Error", error);
}
}
Send();

 

Ruthiel
Product and Topic Expert
Product and Topic Expert

Hello!
I am not sure about the correct SAP Community ID:

Ruthiel_0-1711151851881.png

Ruthiel_1-1711151879814.png

const sentEvent = async () => {
  const response = await axios({
    method: 'post',
    url: restURL + `/TOPIC/dev-challenge/week-3/${sapcommunityid}/ce`,
    data: cloudevent,
    headers: {
      'content-type': 'application/cloudevents+json',
      Authorization: `Basic ${Buffer.from(
        `solace-cloud-client:mcrtp5mps5q12lfqed5kfndbi2`
      ).toString('base64')}`,
    },
  });
  console.log('Status: ', response.status);
};

Nagarajan-K
Explorer

Javascript Code

const axios = require("axios").default;
const { HTTP, CloudEvent } = require("cloudevents");
const baseUrl = "https://mr-connection-plh11u5eu6a.messaging.solace.cloud:9443";
const sapcommunityid = "Nagarajan-K"

// Create a new CloudEvent
const ce = new CloudEvent({
    "specversion": "1.0",
    "type": "com.nk.cloudevents.PurchaseOrder.Created.v1",
    "source": "https://cloudevents.nk.com/PO",
    "subject": "New PO 4500000001 Created",
    "id": "b93ac0f9-86e8-4d85-bbdd-6da5e474ba1d",
    "time": "2024-03-15 07:10:00",
    "datacontenttype": "application/cloudevents+json",
    "sapcommunityid": sapcommunityid,
    "data": {
        "PurchaseOrder": "4500000001",
        "POType": "NB",
        "POOrg": "1000"
    }
})

try {
    axios({
        method: "post",
        url: baseUrl + `/dev-challenge/week-3/${sapcommunityid}/ce`,
        data: ce,
        headers: {
            "content-type": "application/cloudevents+json",
            "authorization": "Basic c29sYWNlLWNsb3VkLWNsaWVudDptY3J0cDVtcHM1cTEybGZxZWQ1a2ZuZGJpMg=="
        }
    }).then(response => {
        console.log(response.status);
        console.log("Cloud Event Triggered Successfully");
    })
} catch (error) {
    console.log("error!");
    console.log(error);
}

Result

NagarajanK_1-1711208382339.png

 

Tried via HTTP Rest Client as well

NagarajanK_0-1711208664967.pngNagarajanK_1-1711208687950.png

 

MatLakaemper
Participant
---------------- Node-Js  ---------
const { CloudEvent, HTTP } = require("cloudevents");
const axios = require('axios');
const dotenv = require('dotenv');

// Load the environment variables from the .env file
dotenv.config();

const {SolaceProtocol, SolaceHost, SolacePort, SolaceUsername, SolacePassword, SapCommunityId, SolaceTopic} = process.env;
const ce = new CloudEvent(
    {
        "type": "sap-business-One-fake",
        "specversion": "1.0",
        "source": "/default/sap.s4.beh/244572008",
        "id": "63d6a150-c6a1-4c5b-bcc3-27d90c07941c",
        "time": "2024-02-26T10:53:06Z",
        "datacontenttype": "application/json",
        "data": {
            "BusinessPartner": "Rübennase",
            "Theme": "Life of Brian"
        },
        "sapcommunityid": `${SapCommunityId}`
    }
);
const { headers, body } = HTTP.structured(ce);

//Output
console.log(
   "Headers:", "\n",
    JSON.stringify(headers, null, 2), "\n",
    "Body:", "\n",
    JSON.stringify(JSON.parse(body), null, 2));

const eventSender = async () => {
    try {
        const response = await axios({
            method: "post",
            url: `${SolaceProtocol}://${SolaceHost}:${SolacePort}/TOPIC/${SolaceTopic}/${SapCommunityId}/ce`,
            data: body,
            headers: {
                ...headers,
                Authorization: `Basic ${Buffer.from(`${SolaceUsername}:${SolacePassword}`).toString("base64")}`,
            },
        });
        console.log("Sending message to the topic: ", `${SolaceTopic}/${SapCommunityId}`);
        console.log("Response Status:", response.status);
    } catch (error) {
        console.error("Error:", error);
    }
}

eventSender();
 
--------- Result ---------------------

npm run start_cloudEventAdvEveMesh
Debugger attached.

> capb2b-main@1.0.0 start_cloudEventAdvEveMesh
> node cloudEventAdvEveMesh.js

Debugger attached.
Headers:
{
"content-type": "application/cloudevents+json; charset=utf-8"
}
Body:
{
"id": "63d6a150-c6a1-4c5b-bcc3-27d90c07941c",
"time": "2024-02-26T10:53:06.000Z",
"type": "sap-business-One-fake",
"source": "/default/sap.s4.beh/244572008",
"specversion": "1.0",
"datacontenttype": "application/json",
"data": {
"BusinessPartner": "Rübennase",
"Theme": "Life of Brian"
},
"sapcommunityid": "MatLakaemper"
}
Sending message to the topic: dev-challenge/week-3/MatLakaemper
Response Status: 200

----- Check Message receipt ----------------------

 

MatLakaemper_0-1711216842052.png

 

 

 
 

dagoca_abapcl
Explorer

Hi  deploy the week 4 challenge code in a GCP Cloud Functions...

 

 

import json
import requests
from flask import jsonify
from cloudevents.http import CloudEvent
from cloudevents.conversion import to_structured

def send_cloud_event(request):
    # Datos de usuario
    username = "David"
    user_last_name = "Gonzalez"
    password = "MTIzNA=="
    country = "CL"
    
    # Crear la CloudEvent
    sapcommunityid = "dagoca_abapcl"
    subject = f"Creacion Usuarios {username}"
    attributes = {
        "type": "com.sap.build.app.Launched.v1",
        "source": "https://cloud.dagoca.com/events/spec/pull",
        "subject": subject,
        "sapcommunityId": sapcommunityid,
    }
    user_data = {
        "name": username,
        "lastName": user_last_name,
        "password": password,
        "country": country,
    }
    event = CloudEvent(attributes, user_data)

    # Convertir CloudEvent a formato estructurado
    headers, body = to_structured(event)

    # Definir la URL de destino
    base_url = "https://mr-connection-plh11u5eu6a.messaging.solace.cloud:9443"
    topic = f"dev-challenge/week-3/{sapcommunityid}/ce"
    url = f"{base_url}/TOPIC/{topic}"

    # Definir las cabeceras
    headers = {
        "content-type": "application/cloudevents+json",
        "authorization": "Basic c29sYWNlLWNsb3VkLWNsaWVudDptY3J0cDVtcHM1cTEybGZxZWQ1a2ZuZGJpMg=="
    }

    # Enviar la solicitud HTTP POST
    try:
        response = requests.post(url, headers=headers, data=body)
        return jsonify({"status_code": response.status_code})
    except Exception as e:
        return jsonify({"error": str(e)})

 

 

dagoca_abapcl_0-1711338288140.png

 

ajmaradiaga
Developer Advocate
Developer Advocate
0 Kudos

Interested in learning more about SAP Integration Suite, advanced event mesh? How about you join us in this in-person event that will take place on the 6th of May @ the SAP office in Madrid, Spain - https://community.sap.com/t5/sap-codejam/event-driven-integrations-with-sap-integration-suite-advanc...

amitcruz
Participant
0 Kudos

@ajmaradiaga :  I am not able to see any consumption of events in week3 CAP app. It has entries till March 26. I published many events today but unfortunately, they are not subscribed. I got '200' response as well. 

Can you check.

0 Kudos

@amitcruzthanks for letting me know... I noticed that the app wasn't processing the messages sent. Fortunately, all the message were in a queue. I restarted the app and your message came through. All good. You can now see them in the app - https://ce-dev-challenge-wk3.cfapps.eu10.hana.ondemand.com/consumed-messages/webapp/index.html.

ajmaradiaga_0-1711708525466.png

 

amitcruz
Participant

Thanks,Antonio for looking into the issue. Here is my submission for Week 3:

amitcruz_0-1711954842629.pngamitcruz_1-1711954871781.png

amitcruz_2-1711954937337.png