MuleSoft Message Structure

Every piece of data that travels through a MuleSoft flow is packaged inside a Mule message. Understanding the message structure is essential because every DataWeave expression, every Logger, and every condition in a router references parts of this message. Think of the Mule message as an envelope carrying a letter — the letter is your data, and the envelope has labels and stamps that describe it.

The Three Parts of a Mule Message

A Mule message has three main parts: the payload, the attributes, and the variables.

Message Structure Diagram

+---------------------------------------------------+
|               MULE MESSAGE                        |
|                                                   |
|  PAYLOAD                                          |
|  { "orderId": "ORD-001",                          |
|    "customer": "Alice",                           |
|    "amount": 250.00 }                             |
|                                                   |
|  ATTRIBUTES                                       |
|  { "method": "POST",                              |
|    "path": "/orders",                             |
|    "headers": { "Content-Type": "application/json"|
|                 "Authorization": "Bearer xyz123" }|
|    "queryParams": { "region": "US" } }            |
|                                                   |
|  VARIABLES                                        |
|  { "customerId": "CUST-456",                      |
|    "discountRate": 0.1 }                          |
+---------------------------------------------------+

Payload

The payload is the main content of the message — the actual data being processed. When an HTTP request arrives with a JSON body, that JSON becomes the payload. When a file is read from disk, the file content becomes the payload. When a database query returns rows, those rows become the payload.

The payload changes as the message moves through the flow. A Transform Message component might convert the payload from JSON to XML. A Database connector might replace the payload with query results.

Payload Changing Through a Flow

HTTP Request arrives:
  Payload = '{"name": "Alice", "email": "alice@email.com"}'
        |
        v
[Transform Message: add timestamp]
  Payload = '{"name": "Alice", "email": "alice@email.com", "created": "2024-01-15"}'
        |
        v
[Database: insert and return ID]
  Payload = [{ "GENERATED_KEY": 1042 }]
        |
        v
[Set Payload: "Customer created with ID 1042"]
  Payload = "Customer created with ID 1042"
        |
        v
HTTP Response returns: "Customer created with ID 1042"

Attributes

Attributes are metadata about the message, not the message content itself. When an HTTP request arrives, the attributes contain information about the request: the HTTP method, the URL path, the query parameters, and the HTTP headers.

Attributes are read-only. You cannot directly change the attributes of an incoming message. Each trigger type produces different attribute types:

  • HTTP Listener: Attributes include method, path, headers, query parameters, and remote address.
  • File connector: Attributes include filename, file size, creation date, and directory path.
  • Scheduler: Attributes include the trigger time.
  • JMS connector: Attributes include message ID, correlation ID, and destination queue name.

Accessing Attributes in DataWeave

// Get the HTTP method
attributes.method           // Returns "POST"

// Get a query parameter
attributes.queryParams.region   // Returns "US"

// Get an HTTP header
attributes.headers.'Content-Type'   // Returns "application/json"

// Get the file name (File connector)
attributes.fileName         // Returns "orders_2024-01-15.csv"

Variables

Variables are values you store during a flow's execution. They persist throughout the entire flow and are accessible in any component after they are set. Variables are like sticky notes you write during processing and refer to later.

Setting and Using Variables

[HTTP Listener: receives order request]
  payload.customerId = "CUST-456"
        |
        v
[Set Variable: name="lookupResult", value=#[payload.customerId]]
  vars.lookupResult = "CUST-456"
        |
        v
[Database: SELECT * FROM customers WHERE id = #[vars.lookupResult]]
  payload = [{id: "CUST-456", name: "Alice", tier: "Gold"}]
        |
        v
[Set Variable: name="customerName", value=#[payload[0].name]]
  vars.customerName = "Alice"
        |
        v
[Logger: "Processing order for #[vars.customerName]"]
  Console: "Processing order for Alice"

Accessing the Message with DataWeave Expressions

DataWeave is MuleSoft's expression language. Expressions let you read and manipulate the message. Expressions are written inside #[ ] brackets.

Common DataWeave Expressions

#[payload]                          // The entire payload
#[payload.orderId]                  // A field inside the payload
#[payload.items[0].price]           // First item's price in an array
#[attributes.method]                // The HTTP method
#[attributes.queryParams.page]      // A query parameter
#[vars.customerId]                  // A variable you set earlier
#[now()]                            // Current date and time
#[uuid()]                           // A unique ID
#[payload.amount * 1.1]             // Calculate 10% tax

The Error Object

When a flow encounters an error, MuleSoft creates an error object. Inside the error handler, you access this error to log details or build a meaningful error response.

Error Object Structure

+------------------------------------------+
|  ERROR OBJECT                            |
|                                          |
|  error.errorType.identifier              |
|    Example: "DB:CONNECTIVITY"            |
|                                          |
|  error.description                       |
|    Example: "Cannot connect to database" |
|                                          |
|  error.detailedDescription               |
|    Full stack trace                      |
|                                          |
|  error.cause                             |
|    Original Java exception               |
+------------------------------------------+

In Error Handler:
[Logger: message="#[error.description]"]
[Set Payload: {"error": "#[error.errorType.identifier]", 
               "message": "#[error.description]"}]

The Null Payload

Some triggers produce a null payload when they fire. A Scheduler trigger, for example, does not carry any data — it simply fires at the scheduled time. After a Scheduler fires, the payload is null. The first processing step usually fetches data to set the payload, like querying a database.

Null Payload Flow Example

[Scheduler: every day at 06:00 AM]
  payload = null  (nothing came in)
        |
        v
[Database: SELECT * FROM orders WHERE status = 'pending']
  payload = [ {id:1, customer:"Alice"}, {id:2, customer:"Bob"} ]
        |
        v
[Logger: "Found #[sizeOf(payload)] pending orders"]
  Console: "Found 2 pending orders"

Immutability of the Mule Message

The Mule message is immutable in each processing step. When a component modifies the payload, it actually creates a new message with the new payload. The original is not changed. This design prevents accidental side effects when multiple threads process messages simultaneously.

From a practical standpoint, this means you do not need to worry about accidentally corrupting the original message. Use Set Variable to save any data you need to preserve before a component replaces the payload.

Leave a Comment

Your email address will not be published. Required fields are marked *