As network speeds and the processing power of devices improves, the size of the files we use to capture our experiences, be they photos or other graphics, videos, or complex documents, increases. We need a way to associate these ever-growing files with the metadata capturing the rest of the experience. This data comes in all shapes and sizes, particularly these days, and as flexible and readable as JSON is, it isn’t great for capturing large amounts of binary bits, but the Experience API specification allows for including attachments with statements for this purpose.

Attachment handling is implemented through a combination of an ‘attachments’ property of the Statement object itself and optional inclusion of copies of the files themselves. Note the use of plurals here, a single Statement may be associated with multiple files, therefore the ‘attachments’ property of a Statement takes an array as its value. The elements of this array are objects with properties, some required and some optional, that provide metadata about the included attachment.

Required Properties

The required properties of an Attachment object are “usageType”, “display”, “contentType”, “length”, and “sha2”. Three of these properties, “contentType”, “length”, and “sha2” describe specifics about the contents of the attachment. The other two indicate how this attachment is to be used related to the Statement’s meaning.

The “contentType” is the RFC2046 media type (or MIME type) of the file, such as “application/pdf” or “text/plain” which instructs a system how the data can be parsed, etc. The “length” property’s value is an integer that specifies the size of the attachment in octets. The “sha2” property’s value is a string representing the SHA-2 hash of the contents and is ultimately what is used to uniquely identify an attachment listed within the statement with the file included in a request. The length of the string value can be used to determine which bit size algorithm was used to generate the hash.

The “display” property takes a language map as its value and gives a human readable name for the attachment similar to the same named property included in a verb. Lastly, the “usageType” property’s value must be a URI (IRI) and describes the “why” of the attachment. The “usageType” serves a similar purpose for Attachments as the “activityType” property does for Activities. (More about usage types below.)

Optional Properties

Along with the required properties, Attachment objects may also include a “description” property and a “fileUrl” property. The former is similar to the “display” property and takes a language map as a value. The language map provides a longer, human readable description of the purpose of the attachment or other information about it. The latter takes a URL from which the attachment’s data can be retrieved, or at least could have at one time. The “fileUrl” property is what makes it optional to include the file contents themselves with requests including the Statement, however either the “fileUrl” or the file itself should be provided when storing the statement.

Here is an example of a Statement with an “attachments” property with a single Attachment object:

{
    …
    "attachments": [
        {
            "contentType": "application/pdf",
            "usageType": "http://id.tincanapi.com/attachment/certificate-of-completion",
            "display": {
               "en-US": "Completion of Experience API 101"
            },
            "description": {
                "en-US": "Certificate provided as proof of completion of Experience API 101 course."
            },
            "length": 63878,
            "sha2": "c2a36cbc4db66444d05e134b85a89681f65263cacd93eb4a544f0bef058a5649"
        }
    ]
}

This example might be included by a course when sending a statement indicating completion of the training, and includes a printable certificate that the participant can provide for compliance reasons.

Inclusion of Files on Requests

Just as with the basic parts of the REST interface the xAPI specification piggybacks on existing, commonly used specifications for inclusion of file attachments in requests, specifically the multipart handling portion of the MIME standard via RFC 1341.

That can be a bit much to take in, so here are the fundamental parts. When including attachments as files in statement requests, the content type of the request becomes “multipart/mixed”. In a multipart/mixed request there will be multiple sections of content separated by block markers, each with a set of headers and a body. The first section (or part) will have the “application/json” content type and the body will contain the normal Statement(s) payload as requests without included files. Each subsequent part will include a special header, specifically the “X-Experience-API-Hash” header, whose value will match the SHA-2 stored in the “sha2” property of the Attachment object of the Statement’s “attachments” property (in other words, what I talked about above). This is how, for a given request, a system can match up the file included in the request with the metadata for that Attachment included in the Statement.

That covers the basics, but there are a lot of rules in the MIME standard about how boundaries between parts are composed, how headers and encodings should be handled, etc. I suggest using a well tested library for MIME handling. Additionally, there are a number of rules about how LRSs and Activity Providers should act when encountering or sending requests with files. Those topics are really best covered by a deep read of the specifications themselves.

Use Cases

The completion certificate example is likely a common use case for attachments for the e-learning industry, but like the rest of the Experience API, there is virtually unlimited scope for what could be handled. Signed electronic contracts for real estate transactions or other types of legal exchanges could be attached to statements. As more retail stores switch to fully electronic operations, receipts could be sent attached to statements for a sale. The TCDraw early prototype captured a dynamically generated image showing a handwriting exercise, at the time attachment support was not yet in the Experience API specification so it uses Extensions, but could (and should) be updated to use attachments instead. Because Attachments include the hash of the contents as an identifier, the same attachment can be easily associated with more than one Statement. For instance you could send your résumé as an attachment when applying for a job, then the hiring manager may include it along with a signed employment contract notifying HR of a new employee. The contents of the file itself may only need to be sent once, but it could be referenced in multiple statements. These are just a couple of use cases, the possibilities are unlimited.

Statement Signing

While each of the use cases above are fairly realistic, the specification includes one use case for attachments, specifically statement signing. A statement may be signed to guarantee the ability to verify authenticity, who is asserting the statement, and integrity, that the statement has not been altered. To do so the original content of the statement is serialized and included in the signature such that it can be later decoded and compared with the recorded statement for logical equivalence. The signature then gets its own entry in the “attachments” array and must have a “usageType” of “http://adlnet.gov/expapi/attachments/signature” per the specification. The signature is then included as a file using the normal attachment procedure. Appendix D of the specification contains an excellent example of what the signature, pre-signed and post-signed Statements look like. Though I’ve not personally seen examples of signed statements in the wild nor support in the libraries, I’m hoping that support is added soon (perhaps I’ll even get to it) and that signed statements start showing up.

Registry for usage types

Attachment usage types are just one more URI that xAPI users have to deal with as we’ve already seen with verbs, activity types, and extensions. To help facilitate interoperability and to make sure attachment usage types are resolvable, The Registry includes handling of “attachment usages”. It contains an ever growing list of usage types that others have already started using, naturally including the statement signature one. In the event that one does not exist that fits your use case, you can easily request to coin a new one that will be added to the list. Usage types like the other shareable URIs are curated and if an existing alternative fits the bill, it may be suggested.

Conclusion

As we saw with other properties of a Statement in “Deep Dive: Extras/Others” the specification does an excellent job of capturing both sides of the metadata requirements when it comes to Attachments. It handles both the mechanical with properties like “contentType”, “length” and “sha2” as well as the meaningful with properties like “usageType” and “display”. Though many of the tools are still being developed to include support for attachments, as the adoption of xAPI matures, more and more experiences will include the capturing of binary data. And for a number of reasons, not the least of which legal ones, statement signing has already been defined to take advantage of this feature to ensure a way to trust statements that have been recorded.

Go now, make statements!

Brian Miller is the Senior Director of Engineering and is also the most pedantic person at the office, which is saying something. That skill makes him great at ensuring our products support the standards, which is precisely what he spends his days doing. Brian is a IEEE LTSC voting member working on the advancement of learning standards, like xAPI and cmi5.