Sharing Documents successfully

So far in this Deep Dive series on the Document API I’ve introduced you to the Document APIs in general and then looked in detail at each Document API in turn. In this final post of the series, we’ll explore two important complexities of the Document APIs that you need to pay particular attention to when multiple Activity Providers or users might be accessing the same Documents.

Sharing keys

As I mentioned in my State and Activity Profile API blog, there is no specific structure or naming convention for Document IDs in any of the Document APIs, but I recommend using IRIs to avoid conflict where two Activity Providers use the same key. This is especially important for the Agent Profile API where it’s more likely for Activity Providers to be accessing the same data. There’s also risk of two Activity Providers storing the same data in different places and missing an opportunity to share (e.g. DOB and dateOfBirth) or using different formats (“27/09/83” vs. “09/27/1983”) and conflicting with one another.

In order to avoid two Activity Providers storing the same data under different structures or using different formats, Communities of Practice will need to define their own Agent Profile Documents IDs and outline the structure and format of Documents they contain. Megan Bowe has done an excellent job of explaining the process of defining a profile within your own community of practice.

Once you’ve defined what data you’re going to store and how you’re going to store it, you should describe it in a Recipe in the Registry. A standard and unique Document ID should be used for each Agent Profile Document. This ensures that Activity Providers using the same Document ID follow the same structure. The Registry doesn’t currently have an area explicitly for registering Document API keys, but you can include them in Recipe descriptions. As Recipes are identified using Activity ids, some Recipes might even encourage APs to store some Documents in the State or Activity Profile APIs at the Recipe Activity id as a mechanism for sharing data between APs implementing that Recipe.

The scope of a community of practice that shares an Agent Profile might vary. A core recipe containing data such as gender might be shared by every Activity Provider implementing xAPI. Other Recipes will be shared by a number of organizations with a shared interest. The draft CMI5 specification, for example, defines a learner preferences document including language and audio preference. Some Recipes may even be specific to a vendor or internal within an organization.

Many Activity Providers using the Agent Profile API will choose to implement multiple Recipes for Agent Profile data. An app and website for parachuting clubs, for example, will make use of gender data from a universal core Recipe, but could follow a parachuting specific Recipe for metrics such as number of jumps, parachute type preference, etc.

ETags and Concurrency

Another risk with multiple Activity Providers or Agents accessing the same Documents is that they could access the Documents at the same time and accidentally overwrite one another’s data. Imagine the following series of events relating to a Document that stores high scores for a mobile learning game:

  • The app on player one’s phone downloads the High Scores Document and inserts his score.
  • Meanwhile, player two completes a game and her phone downloads the High Scores Document and inserts her score
  • Player one’s phone stores the updated High Scores Document with his score.
  • Player two’s phone stores the High Scores Document unaware of the changes made by player one’s phone. His score is lost.

Tin Can makes use of ETags to prevent this happening. Every time a Document is updated, the LRS creates a new ETag for that Document, which it sends to the Activity Provider when they retrieve or store the Document. They then send the ETag back to the LRS when they make changes, telling the LRS which version of the Document they’re trying to modify. The LRS will reject any attempt to store a Document that doesn’t come with the latest ETag. ETags are simply a SHA1 hash of the document and are commonly used in applications across the internet; they’re not unique to xAPI.

In the example above, when player two’s phone tried to store the updated High Scores Document, this would not actually overwrite player one’s score. Instead, the LRS would return an error to player two’s phone to let it know that the Document had changed. The app would then request the latest version of the Document from the LRS and get the latest ETag. It could then choose to try and merge its changes into the latest Document, drop its changes and keep the latest Document or overwrite the latest Document with its own version. You’ll need to choose which option works best in your application.

ETags are required for the Agent Profile and Activity Profile, but Activity Providers can choose whether or not to use them for the State API. I recommend using them anyway to avoid problems. The Tetris Prototype includes an example of using ETags with TinCanJS for the Activity Profile API.

You’ve seen in this post that sharing Documents between Activity Providers requires some effort to get right, but if done properly you should have no problems.

Now that you’ve reached the end of this blog series, you’re ready to start storing and retrieving Documents. All of our code libraries support interacting with the Document APIs. As always, please let us know if you have questions!

Go now, store Documents!