Introduction to Dapr: Part-3

Introduction to Dapr: Part-3

What is PubSub | How to implement PubSub with Dapr and expressJS

Before continuing any further, it is recommended that you read the second part of the series on Introduction to Dapr, as it covers information on different forms of communication and how services are called.

PubSubis a way to connect with other services in an asynchronous manner. Let's take a look at what other features it offers.

Advantages Of Using PubSub With Dapr

  • Pubsub is an integral component of Dapr, allowing for the message broker to be interchangeable and set up as a Dapr Pubsub component. This eliminates the dependence on a specific service, making it more adaptable and portable to changes, even when switching to different message brokers.

  • With Dapr, messages can be exchanged using a standard API, regardless of the programming language used.

  • It also guarantees message delivery at least once and utilizes the CloudEvents 1.0 protocol to provide additional context to the event payload.

  • Dapr is compatible with all major message brokers as a Pubsub component.

How Dapr Handles PubSub

Consider two services, the account service and the user service. When a user is created within the account service, a PubSub message will be sent to the email service, asking it to send a confirmation email as the email service is responsible for delivering these types of emails. To better understand how this works, the service that wants to publish the message (account-service) sends a network request, or API call, to the Dapr Pubsub building block API (account-service Dapr sidecar). This request is wrapped in the specific message broker specified in the configuration, and is then sent to the Dapr sidecar (email-service Dapr sidecar) that has subscribed to that specific subject. Once the message is received, the Dapr sidecar will deliver it to the appropriate service (the email service).

To illustrate how to use PubSub with Express JS, we must take into account two important points. One, Dapr uses redis streams as its default message broker, which we will also be utilizing in this example. Two, it is possible to subscribe to a topic either through a declarative or programmatic method. In this particular example, we will demonstrate how to subscribe to a topic programmatically.

Create account service with index.js file and install express and dapr sdk. Then create a route as shown.

const express = require("express");
const dapr = require("@dapr/dapr");
const app = express();

app.use(express.json());
const client = new dapr.DaprClient(
  "127.0.0.1",
  "3500",
  dapr.CommunicationProtocolEnum.HTTP
);

const pubSubName = "pubsub";
//THIS METHOD TAKE USER AND AFTER CREATING USER IT WILL PUBLISH MESSAGE
app.post("/create", async (req, res) => {
  const topic = "create-user";
  const userId = Math.floor(Math.random() * 100);
  const message = {
    userId,
    name: req.body.name,
    email: req.body.email,
  };
  // Publish Message to Topic :: THIS MESSAGE WILL BE CONSUMED[SUBSCRIBED] IN EMAIL SERVICE
  await client.pubsub.publish(pubSubName, topic, message);
  res.send(message);
});

app.listen("4000", () => {
  console.log("SERVER STARTED ");
});

Here, we are starting the Dapr client with the port 3500 and using the Dapr SDK client to publish the topic called "create-user" so that when the new user is created, this topic is published and the subscribers receive the message.

As previously discussed, we are going to use the default message broker, Redis stream, which has the name PubSub. Run the command stated below to start the service.

dapr run --app-id  account-service --app-port 4000 --dapr-http-port 3500  npm start

Similarly, create an email service with index.js file and install express

const express = require("express");

const app = express();
// Dapr publishes messages with the application/cloudevents+json content-type
app.use(express.json({ type: "application/*+json" }));

const port = 4002;

app.get("/dapr/subscribe", (_req, res) => {
  res.json([
    {
      pubsubname: "pubsub",
      topic: "create-user",
      route: "userCreated",
    },
  ]);
});
//WHEN  topic  "create-user" IS PUBLISHED MESSAGE THE ROUTE IS INVOKED

app.post("/userCreated", (req, res) => {
  console.log(
    " EMAIL SERVICE :: SEND WELCOME  EMAIL TO: ",
    req.body.data.email
  );
  console.log(req.body)
  res.sendStatus(200);
});


app.listen(port, () =>
  console.log(`EMAIL SERVICE listening on port ${port}`)
);

As Dapr utilizes cloud event specifications for transmitting pubsub messages, it is necessary to permit the content-type application/cloudevents+json. We have created the route /dapr/subscribe, which will return an array of objects that include the PubSub name, topic, and route. This route will be accessed by Dapr when the server is launched, and Dapr will automatically subscribe to this topic on behalf of the service. Once the publisher posts a message to this topic, Dapr will proceed along the path specified.

To start the server, execute the command below.

dapr run --app-id  email-service --app-port 4002 --dapr-http-port 3502 npm start

When you use postman to create a user from the account service, you will receive a response similar to this.

{
    "userId": 4,
    "name": "salman",
    "email": "a@b.com"
}

Also if you check the logs of the email service, you will have received EMAIL SERVICE:: SEND WELCOME EMAIL TO: a@b.com. Additionally,a big json object(req.body) will also be logged which will resemble:

{
    "data": {
        "email": "a@b.com",
        "name": "salman",
        "userId": 4
    },
    "datacontenttype": "application/json",
    "id": "9a0afb51-027e-40bc-8b2e-1021e4291048",
    "pubsubname": "pubsub",
    "source": "account-service",
    "specversion": "1.0",
    "topic": "create-user",
    "traceid": "00-486106d71125b78e0d384f64f4b1eee0-8330cfade53e844c-01",
    "traceparent": "00-486106d71125b78e0d384f64f4b1eee0-8330cfade53e844c-01",
    "tracestate": "",
    "type": "com.dapr.event.sent"
}

By utilizing cloud event specifications, we are able to gather extra information along with the data sent by another service. This includes details such as the topic name, pubsub name, source name, and unique id for each message. The actual data will be stored in an object called data. It's important to note that the route handling a specific topic should return a status code of 200 when it receives data as Dapr provides a guarantee of at least one message delivery. If Dapr does not receive a status code of 200, it will assume the message was not successfully received and will continue to send the same message.

Final Words

That concludes the introduction to Dapr’s PubSub .To gain a deeper understanding of PubSub, you can refer to the Dapr documentation and access the code on GitHub. In the next blog post, we will delve into the topic of state management in Dapr.