MuleSoft Choice Router

The Choice Router is MuleSoft's decision-making component. It evaluates conditions and sends the message down one specific path based on the result. Like an if-else statement in programming, the Choice Router makes your flows intelligent by routing different types of data to different processing logic.

How the Choice Router Works

A Choice Router contains multiple when conditions and one default route. When the message reaches the router, MuleSoft evaluates the conditions from top to bottom. The message takes the path of the first condition that evaluates to true. If no condition is true, the message takes the default route.

Choice Router Decision Tree

[Message arrives at Choice Router]
         │
         ▼
When: payload.region == "US"?
  ├── YES → [Route A: process US order]
  └── NO  ↓
         ▼
When: payload.region == "EU"?
  ├── YES → [Route B: process EU order with VAT]
  └── NO  ↓
         ▼
Default → [Route C: process international order]

Choice Router in Anypoint Studio

Drag the Choice component from the Mule Palette (under Core > Routers) onto the canvas. It appears as a branching box. Click the + button inside the Choice component to add more when routes. Each route accepts a DataWeave expression that returns true or false. The Default route at the bottom always exists and acts as the catch-all.

Example 1: Route by Order Type

Routing Orders to Different Systems

Flow: processOrderFlow

[HTTP Listener: POST /orders]
      │
      ▼
[Choice Router]
  │
  ├── When: payload.type == "digital"
  │     [HTTP Request: POST to digital-fulfillment-api/orders]
  │     (no shipping needed for digital items)
  │
  ├── When: payload.type == "physical" and payload.weight > 30
  │     [HTTP Request: POST to freight-api/shipments]
  │     (heavy items go to freight)
  │
  ├── When: payload.type == "physical"
  │     [HTTP Request: POST to standard-shipping-api/packages]
  │     (regular items go to standard shipping)
  │
  └── Default
        [Logger: "Unknown order type: " ++ payload.type]
        [Set Payload: {"error": "Unsupported order type"}]
        [Set Variable: httpStatus = 400]

Example 2: Validate and Branch

Validate Input Before Processing

Flow: createCustomerFlow

[HTTP Listener: POST /customers]
      │
      ▼
[Choice Router: validate required fields]
  │
  ├── When: payload.email == null or payload.email == ""
  │     [Set Payload: {"error": "Email is required"}]
  │     [Set Variable: httpStatus = 400]
  │
  ├── When: !(payload.email matches /^.+@.+\..+$/)
  │     [Set Payload: {"error": "Email format is invalid"}]
  │     [Set Variable: httpStatus = 400]
  │
  ├── When: payload.age < 18
  │     [Set Payload: {"error": "Customer must be 18 or older"}]
  │     [Set Variable: httpStatus = 422]
  │
  └── Default (all validations passed)
        [Database: INSERT INTO customers...]
        [Set Variable: httpStatus = 201]

Example 3: Route by Environment

Flow: notifyOrderShipped

[Choice Router: which notification service?]
  │
  ├── When: p('env') == "production"
  │     [HTTP Request: POST to real-email-service/send]
  │     [HTTP Request: POST to real-sms-service/send]
  │
  └── Default (dev or staging)
        [Logger: "MOCK NOTIFICATION: Order #[vars.orderId] shipped"]
        (no real emails or SMS in non-production)

Nested Choice Routers

You can place a Choice Router inside another Choice Router's route. This is called nesting. Use it when a route itself needs to make a secondary decision.

Nested Router: Region and Tier

[Choice Router: by region]
  │
  ├── When: payload.region == "US"
  │     │
  │     └── [Choice Router: by customer tier]
  │           ├── When: payload.tier == "premium"
  │           │     [Route: same-day shipping, free]
  │           ├── When: payload.tier == "standard"
  │           │     [Route: 2-day shipping, $9.99]
  │           └── Default
  │                 [Route: 5-day shipping, $4.99]
  │
  └── Default (non-US)
        [Route: international shipping, calculate cost]

Using Complex Conditions

Choice Router conditions use DataWeave boolean expressions. Combine conditions with and, or, and not.

Simple condition:
  payload.status == "active"

Combined with AND:
  payload.amount > 1000 and payload.currency == "USD"

Combined with OR:
  payload.priority == "high" or payload.urgent == true

Null check:
  payload.discountCode != null and payload.discountCode != ""

Array check:
  payload.roles contains "admin"

Size check:
  sizeOf(payload.items) > 0

Type check:
  payload.price is Number

Choice Router vs Flow Reference

A Choice Router routes a single message down one path. A Flow Reference calls a subflow regardless of conditions. Use Choice Router when you need conditional routing. Use Flow Reference when you always want to call the same subflow from multiple places.

Returning the Same Response Format from All Routes

When a Choice Router has multiple routes that each produce different payload structures, set a consistent response format at the end. Add a Transform Message component after the Choice Router to normalize all routes' output into a standard shape before returning the response. This makes the API consumer's job much simpler.

Normalize After Routing

[Choice Router]
  ├── When: US order → payload = { "usOrderId": "US-001", ... }
  ├── When: EU order → payload = { "euReference": "EU-002", ... }
  └── Default       → payload = { "intlCode": "INT-003", ... }
      │
      ▼
[Transform: normalize all formats to standard response]
%dw 2.0
output application/json
---
{
  "orderId":  payload.usOrderId default payload.euReference default payload.intlCode,
  "status":   "created",
  "region":   vars.region
}

Leave a Comment

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