- Get Started
- Write Code
Posted by Andrew Downes
Posted 7 May 2015
I’m super excited about the latest recipe we’ve published on the registry! Not only is it a great recipe tackling an important use case, but it was written by adopters who needed it for a real project. It was written incredibly rapidly, going from first draft to ready-to-try in less than two weeks. This blog gives you the details.
Sometimes when I talk to people about recipes, they’re disappointed to hear that there isn’t yet a recipe for the use case they are interested in. “Don’t worry!” I always console them, “You can write your own.” TES took that advice to heart and one of the first things they did after hiring a developer to take Tin Can further in their app was to draft up a recipe covering the events they wanted to track. In this case, attendance at events such as meetings, classroom sessions, conferences, etc.
The actual recipe can be found here in the registry. The recipe is split into ‘Simple Attendance’ which uses a single statement to record that a group attended the event, and ‘Detailed Attendance’ which is used to record more events such as scheduling, registering, joining and leaving. It’s envisaged that some recipe adopters will implement only Simple Attendance whilst others will compliment it with the nuances captured by Detailed Attendance statements.
The bulk of the recipe was written by Sean Donaghy of TES. I helped by reviewing each iteration and making a couple of edits where it was faster to make the change directly than write up an explanation. I’m very happy to help anybody who wants help with reviewing a recipe they’re working on.
This first release of the recipe is considered an alpha version. Aside from the TES developers who are busily implementing the recipe in their product, nobody else has tried the recipe yet. There are likely some changes to come as implementers run into challenges we couldn’t predict. If you do implement the recipe, we really appreciate your comments and feedback. You’ll use the recipe ids (http://xapi.trainingevidencesystems.com/recipes/attendance/0_0_1#simple and http://xapi.trainingevidencesystems.com/recipes/attendance/0_0_1#detailed) as a “category” Context Activity so that when you upgrade to the final release version of the recipe you can easily identify which statements used which version.
Recipes are really important to ensure your statements can be understood by other tools. If you’re working on a Tin Can project and neither following nor writing a recipe, please do get in touch so I can help you.
You can expect this to be the Year of The Recipe for Tin Can. We already had the Open Badges recipe last month and there’s a few more in the works that will pop up as the year progresses. Watch this blog for more news sometime soon!
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 Tin Can. 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 Tin Can.
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 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 Brian Miller
Posted 17 June 2014
As thought leaders in a rapidly progressing community, we’ve tasked ourselves with trying to figure out what the next thing is that the community will want, or more importantly need, to effectively work with the Tin Can API. As the specification approached a 1.0 release, it became apparent that switching the identifiers for Verbs and other Statement parts to URIs was going to leave a gap. Out of that recognition came the Registry. The Registry provides a place for users of the Tin Can API to catalog the various terms they use to construct Statements.
A year later we realized another gap existed—the Tin Can API provides a ton of flexibility, but even the early adopters (innovators in their own right) were having issues implementing effective solutions with so much flexibility. They had too much proverbial rope with which to hang themselves.
Posted by Lizelle van den Berg
Posted 13 June 2014
For the Tin Can API (aka Experience API) to succeed, it needs continuous and consistent use by the community.
But, Tin Can is extremely flexible—which is both a benefit and a curse. One experience might be expressed several different ways by different systems, and this can make reporting difficult.
The community needs a way of using the same words when describing the same experiences. That’s where Recipes come in.
Just as in the cooking world, a recipe is a list of ingredients and a set of instructions. When applied, you get a consistent and expected result that can be provided to others to do the same.
A Recipe is a standard way of expressing an experience. It provides a common language that prevents the use of different words to say the same thing.