- Get Started
- Write Code
Posted by Andrew Downes
Posted 9 March 2015
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.
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.
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:
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!
Posted by Andrew Downes
Posted 2 March 2015
Agents, Personas and People
So far in this Deep Dive series into the Document API we’ve looked at the State API and Activity Profile API. The Agent Profile API is similar to the Activity Profile API, but instead of Documents relating to Activities, it’s used to store Documents relating to Agents, such as the learner. Documents can be stored and retrieved for Agents across Activities, allowing sharing of items such as personal information, user settings, etc. The Agent Profile API can also store Documents such as a reflective learning journal, career plan or development goals. Because this generic information can be shared by multiple Activity Providers, it may be of use even in cases where the Activity Provider has its own data store.
Like the Activity Profile API, the Agent Profile API includes a readonly endpoint for getting information about a particular person. This is known as the Agent Profile Combined Information resource. Agents in xAPI are always a persona, a particular identity. firstname.lastname@example.org, @mrdownes on Twitter and garemoko on GitHub are all separate personas of the same person. See the ‘Gotchas’ section of Brian Miller’s Deep Dive: Actor/Agent for more details. Given that an Agent is only one persona of a person, it may be helpful for an Activity Provider to know if their learner has any other personas the LRS knows about. Maybe @mrdownes has already completed half the learning experience as garemoko; I don’t want to have to start again from scratch!
The Agent Profile Combined Information resource allows an Activity Provider to send the LRS an Agent object and then get back a special Person object that contains all of the identifiers the LRS knows relate to the same person. So for example, if an Activity Provider requested combined information about an agent identified by the e-mail address email@example.com it might get back the following Person object with multiple names, email addresses and accounts:
The specification doesn’t require the LRS to link up personas representing a single person or specify how an LRS should do this if it does. If an LRS does link personas in some way though, this is how an Activity Provider can get at that information. This resource is read-only; Activity Providers can get this information from the LRS, but cannot set it.
The Agent Profile API, and the Person object in particular, is an area where we get a lot of questions. I hope this deep dive has answered some of them, but if you have more questions then please get in touch.
Go now, store Documents!
Posted by Andrew Downes
Posted 23 February 2015
For storing (and sharing) state!
Last time we dived into the Document APIs as a whole. This time we dive deeper into the most well known and commonly used of the Document APIs, the State API. As there’s a lot of similarity between the State API and Activity Profile API (and I don’t have a whole blog worth of content on the State API alone) we’ll cover the Activity Profile API too.
The State and Activity Profile APIs provide a place for Activity Providers that have no storage of their own to store Documents. These APIs are no substitute for an Activity Provider’s own storage, and if you can use your own data store instead, you should. They are useful for small tools for which their own database would be overkill, for converted legacy SCORM content (which would previously have stored data with the LMS), and for new SCORM style content. They can also be useful for communication between a Training Delivery System such as an LMS and the Activity Provider.
Within the State API Documents can be stored on two different levels. First, data can be stored on a per user, per activity basis. Common uses include high scores or bookmarking data. Next, data can be on a per registration, per user, per activity basis. This is used for data specific to a particular launch or attempt. The Activity Provider is responsible for cleaning up after itself and deleting old state documents which are no longer required.
The Activity Profile API is used to store activity wide documents that aren’t specific to an individual learner. This is used in any scenario where interaction between learners is required, for example collaboration activities, social interaction or competition.
Also included in the Activity Profile API is access to the LRS canonical definition of a given Activity. This is retrieved via a Full Activity Object GET request. The Activity Definition can be built up based on the definitions of the Activity given in Statements sent to the Statement API, can be provided in metadata hosted at the location specified by the Activity ID’s IRI or can come from another source used by the LRS. This is a read-only resource and can’t directly be written to by an AP.
It’s recommended that where possible you host a copy of the Activity definition as a JSON document at the Activity Id IRI. This allows the owner of that IRI to assert their canonical definition of the activity and protects against others issuing statements with a conflicting definition. You can host Activity definition metadata yourself, or register your Activity ids within a Profile on the Registry. The LRS will return the canonical definition of the activity within Statements returned via the Statement API when the requested format is ‘canonical’.
The Tetris Prototype uses the Activity Profile API to store a table of high scores shared across all players.
Every Document in the Document APIs has a unique ID, so you can store multiple Documents in each bucket of data. For the State API, this ID is stored in the “stateId” property; for the Activity Profile (and Agent Profile – more on this next blog) the property is “profileId”. This Document ID can be any string, but I recommend using an IRI to avoid conflict with another Activity Provider using the same ID. This is less important when using the State and Activity Profile APIs and targeting an Activity ID you control, but still good practice.
I like to use IRIs for my State IDs to make absolutely sure of avoiding a conflict, but there’s no requirement to do so and the data is already segregated by Activity ID. The spec simply requires the State ID to be a string.
When accessing the State API, the Activity Provider requests a Document matching an Activity ID, Agent object, State ID and, optionally, registration UUID. When accessing the Activity Profile API, Documents are matched only by Activity ID and Profile ID; only the State API can be segregated by registration.
You’ve now covered the State and Activity Profile APIs! Next time we dive into the Agent Profile API!
Go now, store Documents!
Posted by Andrew Downes
Posted 16 February 2015
What are the Document APIs and why should you care?
xAPI’s Statements get a lot of attention and rightly so. Statements are the primary way of tracking the learner and set out a standard data structure for reporting tools to read. But Statements are not the only type of data transmitted via xAPI. xAPI also provides a number of other data buckets (technically known as API Resources) for storage and retrieval of data. Three of these are collectively known as the Document APIs.
Some of you will have also come across the State API, perhaps using it to store bookmarking data for an e-learning course. The Activity Profile and Agent Profile APIs are less well known. They deal with getting and setting data about Activities and Agents respectively, whereas the State API stores data about an Activity/Agent combination. There are some common features the Document APIs share which I’ll cover in this first blog, after which we’ll dive deeper into each in turn.
The Document APIs are primarily designed for storing data that will be retrieved and used either by the Activity Provider storing the data or by another Activity Provider, rather than by reporting tools. They are also used for passing data between a Training Delivery System such as an LMS and an Activity Provider.
The data stored in the Document APIs represents the current situation at a given point in time. If that situation changes, the data will be updated and any old data replaced. Use the Statement API to record a history of what’s happened; use the Document APIs store to the current state of play. For this reason, it’s not considered good practice to build reports based on data in the Document APIs. The data can change at any time so any kind of historical reporting is out of the question. This data might be very useful for a dashboard of KPIs, but most reporting will use the Statement API instead.
The Document APIs store data as “Documents”, like a file on your computer. This means you can store pretty much anything you like in there. This includes text, audio, video, JSON etc. xAPI does not specify a minimum supported storage size, so if you plan to store lots of large documents, you should check with your LRS vendor or make your own storage arrangements.
Documents are stored and retrieved via HTTP request, which means you can send a lot all in one go, but sending too many requests too quickly is resource heavy. For storing a collection of variables, such as bookmarking data, it will often be most efficient to store all your variables as a JSON object in a single document and save these at regular intervals. In a SCORM style course, for example, you can save your bookmarking data every time the learner finishes a slide. Using a POST method instead of a PUT allows you to update individual properties of an object contained in a JSON document, so you can update only those that have changed. This mechanism only works for Documents containing JSON objects, which is a good reason to use JSON objects to store your bookmarking data. We’ll soon be updating our Golf Prototype to include an example of how to achieve this with TinCanJS.
This post has given you an overview of the Document APIs. I’ll follow up next time with a deep dive into the State and Activity Profile APIs. Let me know if you have any questions.
Go now, store Documents!