SfSkills Domains Docs GitHub

Home / integration / dataweave-for-apex

dataweave-for-apex

Use when transforming structured data inside Apex — CSV → JSON, XML → SObject list, JSON → flattened CSV, or schema-mapping a third-party payload to a Salesforce model — and the existing options (`JSON.deserialize`, `Dom.Document` traversal) are too fragile. NOT for MuleSoft Anypoint DataWeave running off-platform (use architect/mulesoft-anypoint-architecture) — use apex/apex-json-serialization.

Open the skill folder on GitHub


DataWeave for Apex

Activate when an Apex method needs to transform between structured formats (CSV ⇄ JSON ⇄ XML ⇄ SObject) and the alternatives — hand-rolled loops over JSON.deserializeUntyped(), Dom.Document traversal, or pulling in a static-resource library — are producing fragile, hard-to-read code. The skill produces a DataWeave script registered as a static resource, the Apex Dataweave.Script caller, and a test fixture; it also rules the feature out when the transformation is trivial enough that built-in Apex parsing is the right answer.


Before Starting

Gather this context before working on anything in this domain:


Core Concepts

What DataWeave for Apex is, and is not

DataWeave for Apex (System.Dataweave / Dataweave.Script) is a Salesforce-native, in-platform implementation of the DataWeave 2.0 transformation language. It is not a runtime call to a MuleSoft instance, and the Salesforce org does not need a MuleSoft license to use it. The DataWeave engine runs inside the Apex transaction's resource envelope: heap, CPU, and the standard Apex governor limits all apply. There is no external network call.

It IS:

It is NOT:

Authoring and registering a script

A DataWeave script is a static resource with a .dwl suffix and a strict header that declares input/output MIME types:

%dw 2.0
input payload application/json
output application/json
---
payload map (item, idx) -> {
    accountName: item.name,
    revenue: item.financials.revenue default 0,
    ownerExternalId: item.owner.externalId
}

The static resource's name is what Apex uses to reference it. Cache control should be Public so the platform can cache the parsed script across executions.

Invoking from Apex

Dataweave.Script myScript = Dataweave.Script.createScript('Account_Mapping_DW');
String inputJson = '[{"name":"Acme","financials":{"revenue":1000000},"owner":{"externalId":"E-1"}}]';
Dataweave.Result result = myScript.execute(
    new Map<String, Object>{ 'payload' => inputJson }
);
String outputJson = result.getValueAsString();

execute accepts a Map<String, Object> whose keys correspond to the input <name> declarations in the .dwl header. The result exposes getValue() (typed) and getValueAsString() (serialized).

Supported input and output MIME types

DataWeave for Apex supports a subset of the full DataWeave MIME catalog. The reliably-available types are:

Less common DataWeave types (Avro, YAML, Parquet) are not currently supported in Apex. Confirm against the current Apex Reference before assuming.


Common Patterns

CSV → SObject list

%dw 2.0
input payload application/csv header=true
output application/json
---
payload map (row, idx) -> {
    Name: row.name,
    Industry: row.industry,
    AnnualRevenue: row.revenue as Number
}

Apex caller deserializes the JSON output into List<Account> via (List<Account>) JSON.deserialize(out, List<Account>.class).

XML → flattened JSON

%dw 2.0
input payload application/xml
output application/json
---
{
    contracts: payload.envelope.contracts.*contract map (c) -> {
        id: c.@id,
        partyName: c.party.name,
        amount: c.amount as Number
    }
}

The *contract syntax handles "one or many" XML repeats safely; @id reads the attribute.

Multi-input merge

A script can declare multiple inputs:

%dw 2.0
input accounts application/json
input owners application/json
output application/json
---
accounts map (a) -> {
    name: a.name,
    ownerName: (owners filter ($.id == a.ownerId))[0].name default "Unassigned"
}

Apex passes both: myScript.execute(new Map<String, Object>{ 'accounts' => accountsJson, 'owners' => ownersJson });.


Decision Guidance

SituationChoiceRationale
3-field-map JSON reshapeJSON.deserializeUntyped + plain ApexScript overhead exceeds benefit on trivial cases
30-field-map with conditionals and defaultsDataWeave-for-ApexScript reads as the spec; Apex equivalent is 200 lines of Map manipulation
XML with deeply nested structureDataWeave-for-ApexDOM traversal in Apex is verbose and brittle to schema drift
CSV → SObject list (large file)Bulk API 2.0 + ingest, not ApexApex CPU and heap are not the right place for >10k-row CSV
Apex Bulk Trigger transformationApex (not DataWeave)Trigger CPU budget is too small to justify script-load overhead per execution
Reusable across many Apex callersDataWeave script (static resource)Single source of truth for the mapping spec

  1. Get a literal sample of the input and a literal sample of the desired output. Without samples, do not write a script.
  2. Decide whether DataWeave is justified — apply the table above. If the Apex equivalent is under ~30 lines and read-once, write Apex.
  3. Author the .dwl script in a scratch org's Developer Console or VS Code with the DataWeave extension. Iterate on the sample inputs until the output matches.
  4. Save as a static resource named with a _DW suffix (convention) and cache control Public.
  5. Wrap the call in an Apex service class so the resource name is in one place: MyMappingService.transform(inputJson). The class should also handle the empty-input, malformed-input, and Dataweave.ExecuteException cases.
  6. Write Apex tests with literal payload strings as fixtures. Assert on the Apex-deserialized output, not on the raw JSON, so structural drift surfaces as a compile error rather than a string mismatch.
  7. Add a check that script-load failures fall back gracefully — createScript throws Dataweave.ScriptException if the resource is missing or malformed.

Review Checklist


Salesforce-Specific Gotchas


Output Artifacts


Package files