autorenew

Kafka Tools on Mac & SpringWolf API Documentation

This article introduces commonly used Kafka connection tools on Mac and how to integrate SpringWolf in SpringBoot projects to generate documentation for async message interfaces.

1. Kafka Connection Tools on Mac

Having a good GUI tool for managing and debugging Kafka on Mac can greatly improve efficiency. Here are some recommended Kafka client tools:

1.1 Offset Explorer (formerly Kafka Tool)

Offset Explorer is a veteran Kafka GUI tool with these features:

Installation:

# Download DMG installer from official website
# https://www.kafkatool.com/download.html

1.2 Conduktor

Conduktor is a powerful Kafka Desktop tool:

Installation:

brew install --cask conduktor

1.3 AKHQ (formerly KafkaHQ)

AKHQ is an open-source Web UI tool:

Quick Start:

docker run -d \
  -p 8080:8080 \
  -e AKHQ_CONFIGURATION="akhq.connections.docker-kafka-server.properties.bootstrap.servers=host.docker.internal:9092" \
  tchiotludo/akhq

1.4 kcat (formerly kafkacat)

kcat is a powerful CLI tool for those who prefer command line:

Installation:

brew install kcat

Common Commands:

# List all Topics
kcat -L -b localhost:9092

# Consume messages
kcat -C -b localhost:9092 -t my-topic

# Produce messages
echo "Hello Kafka" | kcat -P -b localhost:9092 -t my-topic

1.5 Tools Comparison

ToolTypeOpen SourcePriceRecommended For
Offset ExplorerDesktopNoFree/PaidDaily development
ConduktorDesktopNoFree/PaidEnterprise needs
AKHQWebYesFreeTeam sharing, Docker
kcatCLIYesFreeScripting, quick debug

2. Integrating SpringWolf with SpringBoot

SpringWolf is a tool that automatically generates AsyncAPI documentation for Spring projects, similar to what Swagger/OpenAPI does for REST APIs, but specifically for async messaging (Kafka, RabbitMQ, etc.).

2.1 Why SpringWolf?

In microservice architectures, service-to-service communication via message queues is common. Unlike REST APIs, async message interfaces often lack documentation, leading to:

SpringWolf generates standard AsyncAPI documentation by scanning Kafka listeners in your project.

2.2 Add Dependencies

Add SpringWolf dependencies in pom.xml:

<dependency>
    <groupId>io.github.springwolf</groupId>
    <artifactId>springwolf-kafka</artifactId>
    <version>1.8.0</version>
</dependency>

<!-- Optional: Enable UI -->
<dependency>
    <groupId>io.github.springwolf</groupId>
    <artifactId>springwolf-ui</artifactId>
    <version>1.8.0</version>
</dependency>

For Gradle:

implementation 'io.github.springwolf:springwolf-kafka:1.8.0'
implementation 'io.github.springwolf:springwolf-ui:1.8.0'

2.3 Configure SpringWolf

Add configuration in application.yml:

springwolf:
  docket:
    info:
      title: Order Service AsyncAPI Documentation
      version: 1.0.0
      description: Kafka message interface documentation for Order Service
      contact:
        name: Development Team
        email: dev@example.com
    servers:
      kafka:
        protocol: kafka
        host: localhost:9092
    base-package: com.example.order

2.4 Write Kafka Listeners

Use @AsyncListener and @AsyncOperation annotations to document your Kafka consumers:

import io.github.springwolf.bindings.kafka.annotations.KafkaAsyncOperationBinding;
import io.github.springwolf.core.asyncapi.annotations.AsyncListener;
import io.github.springwolf.core.asyncapi.annotations.AsyncOperation;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

@Service
public class OrderConsumer {

    @AsyncListener(
        operation = @AsyncOperation(
            channelName = "order-created",
            description = "Receive order creation events",
            payloadType = OrderCreatedEvent.class
        )
    )
    @KafkaAsyncOperationBinding(groupId = "order-service")
    @KafkaListener(topics = "order-created", groupId = "order-service")
    public void handleOrderCreated(OrderCreatedEvent event) {
        // Handle order creation event
        System.out.println("Received order: " + event.getOrderId());
    }
}

2.5 Define Message Payload

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
@Schema(description = "Order Created Event")
public class OrderCreatedEvent {
    
    @Schema(description = "Order ID", example = "ORD-2024-001")
    private String orderId;
    
    @Schema(description = "User ID", example = "USER-123")
    private String userId;
    
    @Schema(description = "Order Amount", example = "99.99")
    private double amount;
    
    @Schema(description = "Created Time", example = "2024-12-27T10:00:00Z")
    private String createdAt;
}

2.6 Publisher Documentation

For producers, use @AsyncPublisher annotation:

import io.github.springwolf.core.asyncapi.annotations.AsyncPublisher;
import io.github.springwolf.core.asyncapi.annotations.AsyncOperation;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

@Service
public class OrderProducer {
    
    private final KafkaTemplate<String, Object> kafkaTemplate;
    
    public OrderProducer(KafkaTemplate<String, Object> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }
    
    @AsyncPublisher(
        operation = @AsyncOperation(
            channelName = "order-shipped",
            description = "Send order shipped events"
        )
    )
    public void sendOrderShipped(OrderShippedEvent event) {
        kafkaTemplate.send("order-shipped", event);
    }
}

2.7 Access Documentation

After starting the application, access via:

2.8 Complete Project Structure

src/main/java/com/example/order/
├── OrderApplication.java
├── config/
│   └── KafkaConfig.java
├── consumer/
│   └── OrderConsumer.java
├── producer/
│   └── OrderProducer.java
└── event/
    ├── OrderCreatedEvent.java
    └── OrderShippedEvent.java

3. Best Practices

3.1 Naming Conventions

3.2 Documentation Maintenance

3.3 Version Management


4. Summary

Hope this article helps you be more efficient in Kafka development!