Vladimir Dyuzhev, author of MockMotor

Vladimir Dyuzhev
MockMotor Creator

SOAP with Attachments

Add attachments in Response Attachments section.

Why Binary Data?

SOAP and REST services pass the information around in a textual form. The text is so much easier to troubleshoot.

However, not all data are textual. Images and videos, PDFs, native application formats - they all are usually binary. We need to pass these files around, and in an SOA environment, it means to pass them along with SOAP and REST payloads.

How can a text-based service receive or return a binary document without encoding it into base64, which increases its size by 50%?

MIME

The same problem once has already been solved by the designers of email protocols. Mail is also a text-based communication, but we also want to attach binary files to emails.

To enable the attachments in email, the message is split into parts. Each part has its data and content type so that the main part can be a text, and the next ones can contain binary data or anything else:

Content-Type: multipart/mixed; boundary=frontier

This is a message with multiple parts in the MIME format.
--frontier
Content-Type: text/plain

This is the body of the message.
--frontier
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64

PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==
--frontier--

Note that the message parts are separated by a unique boundary string (frontier, tho typically it is random and longer).

MIME is so flexible that it only made sense to re-use it for SOAP for sending attachments.

SOAP with Attachments (SWA)

When a code adds an attachment to a SOAP request or response, it needs to:

1 Set the overall message content type to multipart/related.
2 Generate a random boundary string.
3 Place the main payload into the first section of the message and assign it the right content type (e.g. text/xml).
4 Place the binary attachment(s) to the following sections, each with its content type.

HTTP/1.1 200 OK
Date: Fri, 01 Jun 2018 02:09:53 GMT
Content-Type: multipart/related; type="text/xml"; start="d29fa4f6db1d4ed08c5b6d39eb7422f4"; boundary="c8f00991f64c479ea05d17b3324e8f21"
Transfer-Encoding: chunked

--c8f00991f64c479ea05d17b3324e8f21
Content-Type: text/xml; charset=UTF-8
Content-ID: d29fa4f6db1d4ed08c5b6d39eb7422f4
X-MockMotor-Delay: 500

<soapenv:Envelope xmlns:urn="urn:GetContractSchema"
                  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:GetContractResponse>
         <ContractAttachmentRef>Content-ID-1</ContractAttachmentRef>
      </urn:GetContractResponse>
   </soapenv:Body>
</soapenv:Envelope>

--c8f00991f64c479ea05d17b3324e8f21
Content-Type: application/pdf
Content-ID: <Content-ID-1>
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
...

Note that despite the multipart/related content type is used, SWA doesn’t require the payload to contain a reference (“relation”) to the attachment. The receiving code can typically access the attachments without knowing their names or Content-ID headers.

However, it is a good practice to provide the Content-ID in the payload data. The service response above has the ContractAttachmentRef precisely for this reason.

SWA in MockMotor

MockMotor allows you to add attachments to responses with minimal effort.

All you need to do is:

1 Upload the attachment(s) to the environment.
2 Add the attachment name(s) to the Attachments section of a response.

It is fully scriptable so that you can choose attachments based on request values, account properties or even the random generator. You also have control over attachment content type and Content-ID.

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.

Wait! What About REST?

As far as I know, there is no standard for attaching files to REST/JSON payloads.

However, if someone creates a REST service with attachments, they would most likely use the same MIME structure as in SWA. MockMotor supports adding attachments to REST responses, too, also with full scripting support.

For example, here is a MockMotor self-test service returning a JSON payload and an Excel spreadsheet as an attachment:

HTTP/1.1 200 OK
Date: Fri, 01 Jun 2018 03:14:18 GMT
Content-Type: multipart/related; type="application/json"; start="157940642c0c4370b59f54389022b595"; boundary="d833da0a8e694a30a43f5c1476e9ee36"

--d833da0a8e694a30a43f5c1476e9ee36
Content-Type: application/json; charset=UTF-8
Content-ID: 157940642c0c4370b59f54389022b595
X-MockMotor-Delay: 300

{
  "status":"alright"
}

--d833da0a8e694a30a43f5c1476e9ee36
Content-Type: application/vnd.ms-excel
Content-ID: <Content-ID-1>
Content-Disposition: attachment; name="Environment-Canada-Post-Accounts-3.xlsx"; filename="Environment-Canada-Post-Accounts-3.xlsx"
Content-Transfer-Encoding: binary

PK...

Test Project

You can inspect and play with a SWA response in the mock service I’ve created for this post. The service can be accessed at the MockMotor Demo Site.