Skip to main content

Step 3 - Create Provider (Publisher)

Learning Objectives​

StepTitleConcept CoveredLearning objectivesFurther Reading
step 3Create our Provider with Ports & Adapters in mindHexagonal Architecture
  • Understand how to scaffold an provider application, with ports and adapters in mind
  • Highlight our area of interest for our Pact message verifications
  • TODO LINK

Creating Provider (Publisher)​

For our Provider, we are again going to be following the Ports and Adapters pattern.

We need - a "Port" that is responsible for producing the message. - an "Adapter" that is responsible for sending the message.

In our case, we have a ProductEventService that is responsible for this:

  • The publish is the bit ("Adapter") that knows how to talk to the message queue
  • The update is the bit ("Port") that just deals in our domain and knows how to create the specific event structure.
    • createEvent This is the function on the provider side that we'll test is able to produce the correct message structure.

Port & Adapter

in provider-js-kafka/src/product/product.event.service.js:

const { Kafka, Partitioners } = require("kafkajs");
const { productFromJson } = require("./product");
const { createEvent } = require("./product.event");

const KAFKA_BROKER = process.env.KAFKA_BROKER || "localhost:9092";
const TOPIC = process.env.TOPIC || "products";

class ProductEventService {
constructor() {
this.kafka = new Kafka({
clientId: "product-event-service",
brokers: [KAFKA_BROKER],
});
this.producer = this.kafka.producer({ createPartitioner: Partitioners.LegacyPartitioner });

...

// Port
async create(event) {
const product = productFromJson(event);
// SUT
await this.publish(createEvent(product, "CREATED"));
}
// Port
async update(event) {
const product = productFromJson(event);
await this.publish(createEvent(product, "UPDATED"));
}
// Port
async delete(event) {
const product = productFromJson(event);
await this.publish(createEvent(product, "DELETED"));
}

// Adapter
async publish(message) {
const payload = {
topic: TOPIC,
messages: [{ value: JSON.stringify(message) }],
};

console.log("ProductEventService - sending message:", message);

return this.producer.send(payload);
}
}

module.exports = {
ProductEventService,
createEvent,
};

Target of our test

in provider-js-kafka/src/product/product.event.js:

const createEvent = (product, type) => ({
...product,
event: type,
version: incrementVersion(product.version),
});

const incrementVersion = (v) => {
const version = v ? parseInt(v.match(/[0-9]+/g)[0], 10) + 1 : 1;
return `v${version}`;
};

module.exports = {
createEvent,
};

Step4​

Move onto step 4, where we will create a Pact provider test, which will map our consumer Pact message descriptions to our create event function to ensure it will produce the correct message structure.

Move on to step 4