API-First with AsyncAPI

This is a summary of two long posts about API-First with AsyncAPI and ZenWave AsyncAPI Code Generator.

AsyncAPI and Spring Cloud Streams 3

API-First with AsyncAPI and ZenWave SDK

With ZenWave's spring-cloud-streams3 and jsonschema2pojo plugins you can generate:

  • Strongly typed business interfaces
  • Payload DTOs and
  • Header objects from AsyncAPI definitions.

It uses Spring Cloud Streams as default implementation, so it can connect to many different brokers via provided binders.

And because everything is hidden behind interfaces we can encapsulate many Enterprise Integration Patterns:

  • Transactional Outbox: with MongoDB ChangeStreams, Plain SQL and Debezium SQL flavors
  • Business DeadLetter Queues: allowing you to route different business Exceptions to different DeadLetter queues for non-retrayable errors.
  • Enterprise Envelope: when your organization uses a common Envelope for messages, you can still express your AsyncAPI definition in terms of your business payload.

Broker-based APIs are Symmetric

Because APIs mediated by a broker are inherently symmetric it's difficult to establish the roles of client/server: what represents a publish operation from one side will be a subscribe operation seen from the other side. Also, a given service can act as a publisher and subscriber on the same API.

For these reasons, to avoid defining the same API operations multiple times from each perspective, we propose to define the API only once from the perspective of the provider of the functionality, which may be a producer, a consumer or both.

Some definitions:

  • SERVICE: An independent piece of software, typically a microservice, that provides a set of capabilities to other services.
  • PROVIDER: The service that implements the functionality of the API. It may be accepting asynchronous command request or publishing business domain events.
  • CLIENT/s: The service/s that makes use of the functionality of the API. It may be requesting asynchronous commands or subscribing to business domain events.
  • PRODUCER: A service that writes a given message.
  • CONSUMER: A service that reads a given message.

Define your AsyncAPI from the perspective of the PROVIDER of the functionality, which may be a producer, a consumer or both. Share this definition with your CLIENTS.

Use the table to understand which section of AsyncAPI (publish or subscribe) to use for each topic, and which role (provider or client) to use on the plugin configuration.

EventsCommands
ProviderProduces (publish)Consumes (subscribe)
ClientConsumes (subscribe)Produces (publish)
OperationId Suggested Prefixon<Event Name>do<Command Name>

If you still find confusing which one is a provider and a client just use this rule: it can be only one provider of a given message while clients of a given message there can be many:

  • If the provider is the producer use publish section
  • If is the consumer use subscribe section.

Events, Commands, and Messages

In a messaging system, there are two types of messages: events and commands. An event message describes a change that has already happened, while a command message describes an operation that needs to be carried out. In other words, events are used to notify subscribers about something that has already occurred, while commands are used to initiate an action or process.

  • Event: A message describing a change that has already happened.
  • Command: A message describing an operation that has to be carried out.

Also, while there can be only one provider that produces a given event, but commands can be issued for one or many client producers.

Understanding AsyncAPI Specification

See AsyncAPI Reference and Understanding AsyncAPI Specification blog post for more details about AsyncAPI documents.

Different Styles of Event Messages

See Different Styles of Event Messages to learn about Notification Messages, State Transfer Messages and Domain Event Messages.

API-First Code Generator from AsyncAPI

You can use API-First AsyncAPI Maven Plugin to generate models (DTOs) and a producer implementation.

See Producing Domain Events and Consuming Async Commands for more details on how to configure the plugin, and how to use generated code.

Some Patterns supported by ZenWave AsyncAPI Code Generator

Exception Handling with Business Dead Letter Queue

Populating Headers at Runtime Automatically

Transactional Outbox with MongoDB ChangeStreams

AsyncAPI Conference On Tour Madrid 2023