Study guide

8.4 Calling Mule Flows from DataWeave & Reusing DataWeave Modules

Salesforce Certified MuleSoft Developer I Exam

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Creating Application Networks & API-Led Connectivity

1.1 The IT Delivery Gap & API-Led Connectivity Architecture 1.2 Application Network Foundations & Center for Enablement (C4E) 1.3 Anypoint Platform Architecture & Core Components

2 Chapter 2: Designing APIs with RAML & API Designer

2.1 RAML 1.0 Fundamentals, Data Types & Resource Hierarchy 2.2 Reusable API Fragments, ResourceTypes & Traits 2.3 API Mocking Service, Documentation & Anypoint Exchange Publishing

3 Chapter 3: Accessing and Modifying Mule Events

3.1 Mule 4 Event Architecture: Message, Payload, Attributes & Variables 3.2 Flow Variable Management & Target Variables Pattern 3.3 Accessing Event Metadata, Inbound Attributes & Context Properties

4 Chapter 4: Structuring Mule Applications

4.1 Modular Flow Composition: Flows, Subflows & Private Flows 4.2 Configuration Property Files & Environment Management 4.3 Secure Properties Tool, Encryption & Maven Project Packaging

5 Chapter 5: Building API Implementation Interfaces

5.1 APIkit Scaffolding, Router Configuration & Interface Generation 5.2 HTTP Listener Configuration, Path Matching & Query/URI Parameters 5.3 Interface vs. Implementation Separation & Backend Flow Wiring

6 Chapter 6: Using Connectors & External Systems

6.1 Database Connector: Select, Insert, Update, Stored Procedures & Watermarking 6.2 HTTP Request Connector: Headers, Query Params, Response Timeouts & Target Variables 6.3 Salesforce Connector, JMS Messaging & File/FTP Connectors

7 Chapter 7: Processing Records & Batch Integration

7.1 For Each Scope: Payload Iteration, Batch Size & Streaming Data 7.2 Batch Job Architecture: Input, Process, and Complete Phases 7.3 Batch Step Accept Expression, Failure Handling & Batch Aggregator 7.4 Object Store: Persisting Data Between Flow Executions

8 Chapter 8: Transforming Data with DataWeave 2.0

8.1 DataWeave 2.0 Syntax, Type System & Selectors 8.2 Core Functions: map, filter, pluck, reduce, groupBy & orderBy 8.3 Custom Functions, Format Transformations & Type Coercion 8.4 Calling Mule Flows from DataWeave & Reusing DataWeave Modules

9 Chapter 9: Routing Events & Flow Control

9.1 Choice Router: Conditional Expressions & Default Routing 9.2 Scatter-Gather Router: Parallel Execution, Aggregation & Error Traps 9.3 Async Scope, Round Robin & First Successful Routing 9.4 Validating Mule Events with the Validation Module

10 Chapter 10: Handling Errors & Exception Management

10.1 Mule 4 Error Object Hierarchy & Custom Error Types 10.2 On-Error Continue vs. On-Error Propagate Mechanisms 10.3 Try Scope Exception Isolation & Global Error Handling Strategies

11 Chapter 11: Debugging and Troubleshooting Mule Applications

11.1 Logger Configuration, Categories & Thread/Context Diagnostics 11.2 Anypoint Studio Debugger: Breakpoints, Expression Watches & Step-Through 11.3 MUnit 2.x Testing: Unit Tests, Mocking Connectors & Assertions

12 Chapter 12: Deploying and Managing APIs and Integrations

12.1 CloudHub 1.0 & 2.0 Architecture: Workers, vCores & Clustering 12.2 Runtime Manager: Application Management, Alerts, Insights & Logs 12.3 API Manager: Auto-Discovery, API Gateway, SLA Tiers & Standard Policies

8.4 Calling Mule Flows from DataWeave & Reusing DataWeave Modules

Key Takeaways Explain This Topic AI

Mule::lookup(flowName, payload, timeoutMillis) executes a flow from inside a DataWeave script and returns that flow's resulting payload.

lookup cannot call a subflow — the target must be a <flow> , and only the payload is passed: attributes and variables do not travel with the call.

The default lookup timeout is 2000 ms on CPU_LITE and CPU_INTENSIVE threads; exceeding it raises an error inside the transformation.

MuleSoft deprecated lookup in favour of a Flow Reference with the target attribute, which keeps orchestration in the flow where it can be traced and error-handled.

Reusable DataWeave lives in .dwl files under src/main/resources/modules and is pulled in with import … from dw::…, giving one definition for many transformations.

Last updated: August 2026

Calling Mule Flows from DataWeave & Reusing DataWeave Modules

Most DataWeave scripts are pure: data in, data out. But the exam blueprint contains an objective that breaks that assumption — call Mule flows from a DataWeave script — and a second one about defining and reusing modules, functions, and variables . Both are about the same underlying idea: stop duplicating logic, and reach for shared behavior from inside a transformation.

1. The Mule::lookup Function

The lookup function lives in the Mule module, which DataWeave auto-imports inside a Mule application, so both lookup(...) and the fully qualified Mule::lookup(...) resolve. lookup(flowName: String, payload: Any, timeoutMillis: Number = 2000): Any

  • Parameter Type Purpose
  • flowName String Name of the flow to execute, as a literal string
  • payload Any The payload handed to the target flow

timeoutMillis Number Optional; defaults to 2000 ms on CPU_LITE / CPU_INTENSIVE threads <flow name="enrich-order-flow">

<http:listener config-ref="HTTP_Listener_config" path="/orders" doc:name="Listener"/>

  • <ee:transform doc:name="Enrich With Tax Rate">
  • <ee:message>
  • <ee:set-payload><![CDATA[%dw 2.0
  • output application/json
  • --
  • {
  • orderId: payload.orderId,
  • subtotal: payload.subtotal,
  • taxRate: Mule::lookup("getTaxRateFlow", { country: payload.country }).rate
  • }]]></ee:set-payload>
  • </ee:message>
  • </ee:transform>
  • </flow>
  • <flow name="getTaxRateFlow">
  • <http:request method="GET" config-ref="Tax_API_Config" path="/rates" doc:name="Get Rate"/>
  • </flow>

The transformation calls getTaxRateFlow with a small object, that flow performs the HTTP call, and its resulting payload — { "rate": 0.0825 } — comes back as the value of the lookup expression.

2. The Four Restrictions That Get Tested +-----------------------------------------------------------------------------------------+

  • | WHAT CROSSES THE lookup BOUNDARY |
  • | |
  • | CALLING TRANSFORMATION TARGET FLOW |
  • | payload ---- (only the 2nd argument) ---> payload YES |
  • | attributes ---- X -------------------------> attributes NO (not transmitted) |
  • | vars ---- X -------------------------> vars NO (not transmitted) |
  • | |
  • | RETURN: target flow payload ONLY <-------- (attributes/vars discarded) |
  • +-----------------------------------------------------------------------------------------+

Flows only, never subflows. lookup cannot invoke a <sub-flow> . Passing a subflow name is an error, and "call the subflow with lookup" is a reliable wrong answer.

Payload only, in both directions. Attributes and variables are not transmitted into the target flow, and the target flow returns only its payload. A target flow that reads attributes.queryParams will find nothing there.

It is bounded by a timeout. The default is 2000 ms when the transformation runs on a CPU_LITE or CPU_INTENSIVE thread (one minute on other thread types). A slow downstream call inside the target flow surfaces as a timeout raised inside the transformation , which is a confusing place to debug.

Execution timing is not guaranteed. DataWeave is functional and lazily evaluated, so a lookup whose result is never used may not run at all, and multiple lookups may run in parallel. That makes lookup unsuitable for anything with side effects — never use it to write to a database or publish a message.

Warning

lookup Is Deprecated — Know Both the Function and the Preferred Alternative MuleSoft deprecates lookup and recommends a Flow Reference with the target attribute instead: <flow-ref name="getTaxRateFlow" target="taxRate"/> puts the result in vars.taxRate where the transformation can read it, keeps orchestration visible in the flow, and lets normal error handlers catch failures. The exam can test either the function's mechanics or the recommendation, so learn both. <!-- Preferred: orchestration stays in the flow, result lands in a variable -->

  • <flow-ref name="getTaxRateFlow" target="taxRate" doc:name="Get Tax Rate"/>
  • <ee:transform doc:name="Build Response">
  • <ee:message>
  • <ee:set-payload><![CDATA[%dw 2.0
  • output application/json
  • --
  • { orderId: payload.orderId, taxRate: vars.taxRate.rate }]]></ee:set-payload>
  • </ee:message>
  • </ee:transform>
  • 3. Reusing DataWeave: Variables, Functions, and Modules

The same blueprint domain expects candidates to define, use, and reuse DataWeave constructs. There are three levels, and questions usually turn on picking the right one.

  • Construct Declared with Scope Use when
  • Header variable var taxRate = 0.0825 One script A constant or precomputed value used repeatedly in that script
  • Header function fun net(g) = g * 0.9 One script Logic reused several times inside that script
  • Module ( .dwl file) import … from dw::… Whole application Logic reused across several transformations
  • Building a Custom Module

A reusable module is a .dwl file placed under src/main/resources/modules/ . The file path becomes its import path: src/main/resources/modules/OrderUtils.dwl is imported as modules::OrderUtils . // src/main/resources/modules/OrderUtils.dwl

%dw 2.0

var STANDARD_DISCOUNT = 0.05

  • fun applyDiscount(amount: Number, rate: Number = STANDARD_DISCOUNT): Number =
  • amount - (amount * rate)
  • fun tierOf(total: Number): String =
  • if (total >= 10000) "PLATINUM"
  • else if (total >= 1000) "GOLD"
  • else "STANDARD" %dw 2.0
  • import applyDiscount, tierOf from modules::OrderUtils
  • output application/json
  • --
  • payload map (order) -> {
  • orderId: order.id,
  • payable: applyDiscount(order.total),
  • tier: tierOf(order.total)
  • }
  • The Three Import Forms
  • Form Effect
  • import dw::core::Strings Members must be qualified: Strings::capitalize(x)
  • import capitalize, words from dw::core::Strings Named members callable directly: capitalize(x)
  • import * from dw::core::Strings Every member callable directly; risks name collisions

Important

Modules Are Not Auto-Imported — Except a Few dw::Core is imported automatically, which is why map , filter , sizeOf , and now() work with no header line. Everything else — dw::core::Strings , dw::core::Arrays , dw::core::Binaries , and your own modules — needs an explicit import . An exam snippet that calls capitalize() with no import is broken, and the missing import is the defect the question is pointing at.

Tip

Reuse Across Applications Goes Through Exchange A module shared by one application belongs in src/main/resources/modules . Logic shared by many applications belongs in a library published to Anypoint Exchange and pulled in as a Maven dependency, which is the same reuse story as RAML fragments one layer down.