Skip to main content

Mosaic Messaging

Contracts

Mosaic services use a design-first approach for messaging definitions. Messaging is described in the form of contracts. JSON Schema files define each command and event message payload. The AsyncAPI specification is used to document for every payload which RabbitMQ routing key and target queue to use.

Messaging contracts are not only playing the role of a single source of truth but also:

  • Provide a transparent process for managing messages.
  • Serve as documentation.
  • Source for code generation.
  • Extendable: define once, generate code for multiple technologies and e2e tests.
  • Can be exchanged with third parties for integration.

AsyncAPI Specification

AsyncAPI specification, an adaptation of the OpenAPI specification, allows to describe Messaging endpoints in a simple and readable format. The specification can be provided in JSON or YAML formats.

AsyncAPI Specification: 'example-asyncapi.yml'

asyncapi: 2.0.0
info:
title: Example Service
version: '1.0.0'
description: |
Example Management
# Mosaic extension for AsyncAPI specification, used to define service id. If not defined, as service id will be used info.title in lower-kebab-case
x-service-id: ax-service-example

channels:
# command
'example.create': # RabbitMQ routing key
bindings:
amqp:
queue:
name: inbox # RabbitMQ queue name should always be "inbox"
publish:
message:
# reference to message definition under `components/messages` section of document
$ref: '#/components/messages/example-create-command'
components:
messages:
example-create-command:
tags:
- name: aggregate-type:example # defines the aggregate type "example"
contentType: application/json
payload:
# reference to the location of the file with JSON schema for the message payload
$ref: 'commands/create-example-command.json'

Message

RabbitMQ allows to send messages with textual or binary message bodies. Based on the content-type, the consumer can check how to deserialize the message.

Mosaic-based messages use JSON as the message format. All messages share a common message structure that defines the message payload (custom defined) but also the metadata for exchanging messages. The metadata allows for a common way to log/trace messages, define the message type, carry the authentication token, share context, etc. The business-relevant data is contained in the payload field.

Example message (with a shortened auth_token)
{
"payload":{
"title": "Example Title 1",
"count": 3
},
"message_context":{
"example_correlation_id": "9b9824d7-5af1-45c2-9f5d-32423f0d6d39"
},
"message_id":"3eb8257f-1341-49fb-bf77-027549cd4761",
"timestamp":"2024-03-02T08:56:22.555Z",
"message_type":"ExampleCreateCommand",
"aggregate_id": "3",
"aggregate_type": "example",
"message_version":"1.1",
"auth_token":"eyJhbGcixxx.eyJ0ZW5hbnRJZCxxx.VYqnlcLWxxx"
}

Message field definitions

PropertyDescription
payloadThe Actual message payload/content.
message_contextAn object that provides contextual information. This object can be attached to messages. When the initial message contains a message context, it should be included in every event that is published when handling that message. This is especially useful when sending a command where the resulting event should be mapped back to the starting entity.
message_idThe unique message identifier as UUID.
timestampDate and time (UTC) when the message was first published.
message_typeMessage type, e.g. EnsureVideoExistsStart.
aggregate_idThe unique identifier of the aggregate/entity this message is based on.
`aggregate_type``The name of the aggregate of this message e.g. video.
message_versionA version string of the message version. Can be increased if a new message format is created, so both the old and new message format can be correctly handled.
auth_tokenA JWT token of the user/actor who triggered the message publication.

The message payload is defined using a JSON schema because of its powerful expressive features and mature (and abundant) tooling.

The following is an example of how a command message payload can be defined.

Message Definition: 'commands/create-example-command.json'
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type":"object",
"title": "create_example_command",
"description": "Create example command schema.",
"additionalProperties": false,
"required": ["title", "count"],
"properties": {
"title": {
"type": "string",
"description": "The title of the example entity."
},
"count": {
"type": "integer",
"description": "Some example count."
}
}
}