Multipart (Form Data) Format

MIME type: multipart/form-data

ID: multipart

DataWeave supports Multipart subtypes, in particular form-data. These formats enable you to handle several different data parts in a single payload, regardless of the format each part has. To distinguish the beginning and end of a part, a boundary is used and metadata for each part can be added through headers.

DataWeeave represents a Multipart document with the given Object structure:

type Multipart = {
  preamble?: String,
  parts: {
    _?: MultipartPart
  }
}
type MultipartPart = {
  headers?: {
    "Content-Disposition"?: {
      name: String,
      filename?: String
    },
    "Content-Type"?: String
  },
  content: Any
}

Examples

The following examples show uses of the Multipart format.

Example: Multipart

This example shows how DataWeave reads simple Multipart content.

Input

The Multipart input serves as the payload to the DataWeave source.

--34b21
Content-Disposition: form-data; name="text"
Content-Type: text/plain
Book
--34b21
Content-Disposition: form-data; name="file1"; filename="a.json"
Content-Type: application/json
{
"title": "Java 8 in Action",
"author": "Mario Fusco",
"year": 2014
}
--34b21
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html

<title> Available for download! </title>
--34b21--

Source

The DataWeave script transforms the Multipart input payload to the DataWeave (dw) format.

%dw 2.0
output application/dw
---
payload

Output

The output shows how the DataWeave (dw) format represents the Multipart input. Note that the raw and content values are shortened for brevity. The full values are longer.

{
    parts: {
        text: {
            headers: {
                "Content-Disposition": {
                    name: "text",
                    subtype: "form-data"
                },
                "Content-Type": "text/plain"
            },
        content: "Book" as String {
            raw: "Qm9vaw==" as Binary {
                    base: "64"
                },
                encoding: null,
                mediaType: "text/plain",
                mimeType: "text/plain"
            }
        },
        file1: {
            headers: {
                "Content-Disposition": {
                    name: "file1",
                    filename: "a.json",
                    subtype: "form-data"
                },
                "Content-Type": "application/json"
            },
            content: {
                title: "Java 8 in Action",
                author: "Mario Fusco",
                year: 2014
            } as Object {
                raw: "ewogICJ0aXRsZSI6ICJKYXZhI...==" as Binary {
                    base: "64"
                },
                encoding: null,
                mediaType: "application/json",
                mimeType: "application/json"
            }
        },
        file2: {
            headers: {
                "Content-Disposition": {
                    name: "file2",
                    filename: "a.html",
                    subtype: "form-data"
                },
                "Content-Type": "text/html"
            },
            content: "PCFET0NUWVBFIGh0bWw+Cjx0aXRsZT4KI...==" as Binary {
                base: "64"
            }
       }
    }
}
----

Example: Access and Transform Data from Parts

Within a DataWeave script, you can access and transform data from any of the parts by selecting the parts element. Navigation can be array-based or key-based when parts feature a name to reference them by. The part’s data can be accessed through the content keyword, while headers can be accessed through the headers keyword.

Input

This example serves as input to separate DataWeave scripts. shows a raw multipart/form-data payload with a 34b21 boundary consisting of 3 parts:

  • a text/plain one named text

  • an application/json file (a.json) named file1

  • a text/html file (a.html) named file2

Raw Multipart Data:
--34b21
Content-Disposition: form-data; name="text"
Content-Type: text/plain

Book
--34b21
Content-Disposition: form-data; name="file1"; filename="a.json"
Content-Type: application/json

{
  "title": "Java 8 in Action",
  "author": "Mario Fusco",
  "year": 2014
}
--34b21
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html

<!DOCTYPE html>
<title>
  Available for download!
</title>
--34b21--

Source

The following DataWeave script uses the raw multipart/form-data payload as input to produce Book:a.json.

Reading Multipart Content:
%dw 2.0
output text/plain
---
payload.parts.text.content ++ ':' ++ payload.parts[1].headers.'Content-Disposition'.filename

Example: Generate Multipart Content

You can generate multipart content that DataWeave uses to build an object with a list of parts, each containing its headers and content. The following DataWeave script produces the raw multipart data (previously analyzed) if the HTML data is available in the payload.

Writing Multipart Content:
%dw 2.0
output multipart/form-data
boundary='34b21'
---
{
  parts : {
    text : {
      headers : {
        "Content-Type": "text/plain"
      },
      content : "Book"
    },
    file1 : {
      headers : {
        "Content-Disposition" : {
            "name": "file1",
            "filename": "a.json"
        },
        "Content-Type" : "application/json"
      },
      content : {
        title: "Java 8 in Action",
        author: "Mario Fusco",
        year: 2014
      }
    },
    file2 : {
      headers : {
        "Content-Disposition" : {
            "filename": "a.html"
        },
        "Content-Type" : payload.^mimeType
      },
      content : payload
    }
  }
}

Notice that the key determines the part’s name if the name is not explicitly provided in the Content-Disposition header, and note that DataWeave can handle content from supported formats, as well as references to unsupported ones, such as HTML.

The following example shows how to send the current payload as a file part in a multipart form-data. You need to use a DataWeave script similar to the following:

%dw 2.0
input payload application/xml
output multipart/form-data boundary="----myboundary----"
---
{
  parts: {
    filePart: {
      headers: {
        "Content-Disposition": {
          "name": "<NAME>",
          "filename": "<FILE_NAME>.<FILE_EXTENSION>"
        },
        "Content-Type": "<FILE_CONTENT-TYPE>"
      },
      content: payload
    },
    otherJsonPart: {
      content: '{"name": "sampleFile.xml", "sampleFile": {"type": "sample"} }'
    }
  }
}
  • boundary sets the boundary value, for example "----myboundary----".

  • <NAME> is the tag name of your file, for example "sampleFile".

  • <FILE_NAME>.<FILE_EXTENSION> is the filename to populate the payload content, for example "sampleFile.xml".

  • <FILE_CONTENT-TYPE> matches the content of the file you send, for example "application/xml".

  • The content of the file is the current payload.

This example contains two parts in the multipart which are the file and the otherJsonPart. In case you want to add more parts, add them under the parts:{} section with the following format:

  <PART_NAME>: {
    content: <PART_CONTENT>
  }
  • <PART_NAME> is the name of the part without quotes, for example json.

  • <PART_CONTENT> is the content for that part, for example '{"name": "sampleFile.xml", "sampleFile": {"type": "sample"} }'.

Based on the following XML input:

<Customers>
	<Customer>
		<Number>1</Number>
		<FirstName>Fred</FirstName>
		<LastName>Landis</LastName>
		<Address>
			<Street>Oakstreet</Street>
			<City>Boston</City>
			<ZIP>23320</ZIP>
			<State>MA</State>
		</Address>
	</Customer>
	<Customer>
		<Number>2</Number>
		<FirstName>Michelle</FirstName>
		<LastName>Butler</LastName>
		<Address>
			<Street>First Avenue</Street>
			<City>San-Francisco</City>
			<ZIP>44324</ZIP>
			<State>CA</State>
		</Address>
	</Customer>
	<Customer>
		<Number>3</Number>
		<FirstName>Ted</FirstName>
		<LastName>Little</LastName>
		<Address>
			<Street>Long Way</Street>
			<City>Los-Angeles</City>
			<ZIP>34424</ZIP>
			<State>CA</State>
		</Address>
	</Customer>
</Customers>

The DataWeave script is:

%dw 2.0
output multipart/form-data  boundary="----myboundary----"
---
{
  parts: {
    filePart: {
      headers: {
        "Content-Disposition": {
          "name": "test",
          "filename": "sampleFile.xml"
        },
        "Content-Type": "application/xml"
      },
      content: payload
    },
    otherJsonPart: {
      content: '{"name": "sampleFile.xml", "sampleFile": {"type": "sample"} }'
    }
  }
}

The output multipart is:

------myboundary----
Content-Type: application/xml
Content-Disposition: form-data; name="test"; filename="sampleFile.xml"

<Customers>
  <Customer>
    <Number>1</Number>
    <FirstName>Fred</FirstName>
    <LastName>Landis</LastName>
    <Address>
      <Street>Oakstreet</Street>
      <City>Boston</City>
      <ZIP>23320</ZIP>
      <State>MA</State>
    </Address>
  </Customer>
  <Customer>
    <Number>2</Number>
    <FirstName>Michelle</FirstName>
    <LastName>Butler</LastName>
    <Address>
      <Street>First Avenue</Street>
      <City>San-Francisco</City>
      <ZIP>44324</ZIP>
      <State>CA</State>
    </Address>
  </Customer>
  <Customer>
    <Number>3</Number>
    <FirstName>Ted</FirstName>
    <LastName>Little</LastName>
    <Address>
      <Street>Long Way</Street>
      <City>Los-Angeles</City>
      <ZIP>34424</ZIP>
      <State>CA</State>
    </Address>
  </Customer>
</Customers>
------myboundary----
Content-Disposition: form-data; name="otherJsonPart"

{"name": "sampleFile.xml", "sampleFile": {"type": "sample"} }
------myboundary------

Example: Iterate through Multipart payload

This example shows how DataWeave iterates through all the parts of the payload and processes the each part individually.

Source

%dw 2.0
output application/json
var multi = '--34b21
Content-Disposition: form-data; name="text"
Content-Type: text/plain

Book
--34b21
Content-Disposition: form-data; name="file1"; filename="a.json"
Content-Type: application/json

{
"title":"Java 8 in Action",
"author":"Mario Fusco",
"year":2014
}
--34b21
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html

<!DOCTYPE html>
<title>
Available for download!
</title>
--34b21--'
var parsed = read(multi, "multipart/form-data", {boundary:'34b21'})
---
parsed.parts mapObject ((value, key, index) -> {(index): key})

Output

{
  "0": "text",
  "1": "file1",
  "2": "file2"
}

Configuration Properties

DataWeave supports the following configuration properties for this format.

Reader Properties

This format accepts properties that provide instructions for reading input data.

Parameter Type Default Description

boundary

String

null

The multipart boundary value. A string to delimit parts.

defaultContentType

String

This property has no default value.

Sets the default Content-Type to use on parts of the multipart/* format. When set, this property takes precedence over the system property setting for com.mulesoft.dw.multipart.defaultContentType. Introduced in DataWeave 2.3 (2.3.0-20210720) for the August 2021 release of Mule 4.3.0-20210719.

Writer Properties

This format accepts properties that provide instructions for writing output data.

Parameter Type Default Description

boundary

String

null

The multipart boundary value, a string to delimit parts.

bufferSize

Number

8192

Size of the buffer writer.

deferred

Boolean

false

Generates the output as a data stream when set to true, and defers the script’s execution until consumed.

Valid values are true or false.

Supported MIME Types

This format supports the following MIME types.

MIME Type

multipart/*

Was this article helpful?

💙 Thanks for your feedback!

Edit on GitHub