Vladimir Dyuzhev, author of MockMotor

Vladimir Dyuzhev
MockMotor Creator

SOAP Attachments with MTOM/XOP

Switch MTOM/XOP on in the Response Attachments section of the mock response.

What’s wrong with SWA?

Previously I described SOAP with Attachments (SWA) and how to use it in MockMotor.

SWA is still in use today, but another specification became the standard instead: MTOP/XOP. Why?

The main reason is that the attachments in SWA are not logically a part of the response. They are separate parts, and, from the code point of view, that causes unnecessary efforts.

Consider this SWA pseudo-code:

Response resp = callReportsService();
Report report = readPayload(resp);
byte[] reportPDF = readAttachment(resp);

The report meta-data and the report itself (as a PDF) are in two different objects.

The developers very much prefer this:

Response resp = callReportsService();
Report report = readPayload(resp); // report already contains the attachment as a pdf field

The difference seems little at first glance, but it grows fast when you need to receive two or more attachments.

Imagine a meeting appointment where each participant has its own avatar picture. In SWA, each avatar is sent as an attachment. The code then would have to retrieve every attachment and find the proper place in the data structure to save that avatar. This is a mindless and error-prone work, which SWA forces us to do.

Hence comes MTOM/XOP.

MTOM/XOP

MTOM relies on application frameworks to extract the attachments from the SOAP messages and place them into the data objects. To do that it needs two things:

1 The XML element, which contains (actually, refers to) an attachment should have XSD type of base64Binary.
2 The reference value in that element matches one of the attachments' Content-ID headers.

When these two conditions satisfied, the framework’s code can find the attachment by Content-ID, convert it into bytes array and assign to the data object.

In the example below, the data element must be defined as xsd:base64Binary in the service WSDL. The xop:Include element in the response tells the receiving code that the actual value of the data element should be read from an attachment with the Content-ID of ATT1:

HTTP/1.1 200 OK
Date: Thu, 31 May 2018 03:29:38 GMT
Content-Type: multipart/related; type="application/xop+xml"; boundary="1cfbcfcf5bd24ac4ac8c84e2d431bac7"; start="daf16aee1529464db80c1874f81d01b3"; start-info="text/xml"

--1cfbcfcf5bd24ac4ac8c84e2d431bac7
Content-Type: application/xop+xml; charset=UTF-8; type=text/xml
Content-ID: daf16aee1529464db80c1874f81d01b3

    ... SOAP response payload is here ...
    <data>
        <xop:Include href="cid:ATT1" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
    </data>
    ...

--1cfbcfcf5bd24ac4ac8c84e2d431bac7
Content-Type: application/pdf
Content-ID: <ATT1>
Content-Disposition: attachment; name="contract.pdf"; filename="contract.pdf"
Content-Transfer-Encoding: binary

%PDF-1.7
1308 0 obj
<</Linearized 1/L 643967/O 1314/E 57853/N 5/T 643378/H [ 753 544]>>
endobj
...
--1cfbcfcf5bd24ac4ac8c84e2d431bac7--

MTOM/XOP in MockMotor

To configure a response with XOP attachments:

1 Upload the attachment(s) to the environment.
2 Add the attachment name(s) to the Attachments section of a response.
3 In the same section, set the attachment style to MTOM/XOP.

Instead of attachment names, you can use a script to choose an attachment based on account id or other conditions.

For example, here, the first attachment’s name and Content-ID are taken from the mock account properties, and the second one is conditional on the request element <tos/>.

(
    <attachment>
      <name>{$account/*:contractName}</name>
      <content-id>{concat('CID',$account/*:id)}</content-id>
    </attachment>,
    if( $input//*:tos ) then 
      <attachment>
      <name>Standard TOS.pdf</name>
      </attachment>
    else ()
)

Read more about configuring the attachments in the Response Attachments documentation.

Not for REST/JSON

MTOM/XOP is for SOAP only, because it depends on the distinctive element in the XOP namespace to recognize the places where the attachment binary data should be inserted when parsing the payload. JSON attachments cannot have this element (or at least it is not defined for them).

Test Project

I have created a test XOP mock service for this post. The service can be accessed at the MockMotor Demo Site.