Building a Learning Record Store
Ready to build your own LRS? We’ll walk you through everything you need to know to get started.
Building a Learning Record Store
Developing an Learning Record Store (LRS) from scratch is not a trivial undertaking. The first step is to get an in-depth understanding of the complete xAPI specification itself. When you develop an activity provider, you can use just the parts of the specification you need, and can test against an LRS to make sure you’re doing it right. That’s not true when developing an LRS. LRSs have to be able to handle every possible request an activity provider could send and are responsible for validating those requests. We deliberately designed the spec like this to make it as easy as possible to develop activity providers. The flip side of that decision is that building an LRS is hard.
To build an LRS, you first have to decide if the LRS will be a component of an LMS or a standalone, enterprise LRS. If you decide to build your LRS as part of an LMS, there’s a guide that handles how xAPI content should be imported, launched and how to deal with private access to content. Read more about launching xAPI experiences here.
Below is the bare minimum functionality you will need to implement, no matter which type of LRS you decide to build.
The APIs
The Experience API is really a collection of four RESTful APIs. In talking about xAPI, many focus on statements and transferring them between LRSs, this is the job of the statement API. The Document APIs: State, Activity, and Agent don’t deal with statements, they allow for richer information to be stored (a string, an image, a Word document, a video, etc — the document APIs are about these other pieces of data that don’t belong in a statement). To build an LRS, you have to implement all four APIs.
The statement API is the way to put statements into an LRS and to get statements from an LRS. You can get and put a single statement or multiple statements with this API. This is the API you would use to pull down statements from an LRS to fuel reporting and visualizations.
Statements range in size. Today we often see fairly small statements, but there is potential for very large statements. Adding attachments in 1.0 increases the likelihood of seeing larger statements regularly. An LRS needs to determine how large is too large for a statement, this needs to be carefully decided so it doesn’t limit common use cases for the users. The LRS needs to effectively balance storing and working with large statements while efficiently handling smaller statements.
The state API is generally used by activity providers as a scratch space to support learning activities while they’re in progress. Saving state in this way allows resumption of an activity across sessions and across devices.
Example:
An example for using this API could be a person editing an image as part of a learning activity, that image could be saved (as an image) in the LRS with the state API. The different states of the image could be pulled back by the application at the end to put together a collection that shows the changes in the work over time.
The Activity API stores data about activities in the LRS. There should be a full description of each activity in the LRS that can be referenced through this API. The LRS bears the responsibility for determining the best definition for each unique activity it has received. Part of the LRS’s responsibility for determining an activity’s definition is to attempt to access the activity’s metadata – care should be taken to avoid blocking requests when doing this.
Example:
For team simulations, an activity could store its state under its own profile instead of with the State API. The state API is specific to Agent, the Activity API is not agent specific. Screenshots or pictures of real life training could be stored with this API. It’s a way to store documents that represent people showing their work with the activity.
Another example, in our Tetris prototype you will see a call to store high scores across the users in the LRS as a document for the activity with the Activity API. This populates a leaderboard much more quickly than by deriving high scores across all of the statements for the Tetris activity each time the user requests to see the leaderboard.
The Agent API is similar to the State and Activity APIs, but it’s focused on adding additional data about agents to the LRS. The Agent API is a way to connect the different ways a person has been identified across an LRS by adding the different IDs and credentials to the Agent.
Example:
An avatar that represents the person could be added to their profile in the LRS through the Agent API. An avatar image is not something that would be sent with a statement. When other permissed systems queried the LRS for the profile, they could pull in this image file to populate for the person in their system.
Security and Authentication: Permissions and OAuth
An LRS has to support authentication, and the most common two authentication mechanisms are HTTP basic authentication and oAuth. If an LRS is going to support oAuth, then it has to implement the various requirements listed below. oAuth is a commonly used specification for authentication on the web. For example, this image illustrates a music site and Facebook connecting with oAuth. In most of the Experience API world, the consumer would be an application and the provider would be the LRS. LRSs can also connect to each other. Once connected they can use the Statement API to share statements.
There are five scenarios in the xAPI spec:
- The application is a known oAuth consumer and the person is known
- The application is a known oAuth consumer and the person is not known
- The application is not a known oAuth consumer but the person is known
- There is no application and the person is known
- There is no authentication – blank credentials are used for testing purposes only.
In the authorization process, the Experience API spec has specific ways that tokens, authorizations, and temporary credentials need to work with endpoints.
If an oAuth connection is made, the scope of the data that can be shared through the statement API is defined. An LRS has to support the scopes defined in oAuth 2.0.
The LRS is responsible for populating (or validating) the authority portion of the statement, based on the credentials used to send the statement. There are specific requirements for constructing an authority based on each type of authentication.
Statement Transfer: Retrieval
Retrieving a collection of statements from an LRS and storing them locally to support reports or visualizations is the best way to work with the data. Constantly querying the LRS is less effective because it’s a big load. Pulling down the data also allows you to do more in-depth queries of the data because the statement API doesn’t query on all statement parameters (extensions, for example, can not be queried with the statement API). See Reporting for more details.
An LRS will need to carefully index data because efficiently serving the queries can be complex. One challenge is efficiently handling relationships between statements. An example of this would be if a search for certain conditions that match statement C must return statement A. Then if A targets B which targets C, all three must be returned, as described in filter conditions for statement refs. Statement references are ways to point to another statement as important to the referencing statement.
When a query for statements is made to the LRS, it returns a number of statement results and generates a URL, which has to remain active for 24 hours to allow for more statements to be pulled down. There are also guidelines about the length of URLs and storage of query data, that’s all in the spec too.
Data Quality
The LRS has specific responsibilities when it comes to voided statements. This is because xAPI statements are immutable. They cannot be deleted. A false or inaccurate statement can only be voided. The burden is on the LRS to make sure that the original flawed statement is dealt with appropriately so it doesn’t mire reports and other ways that the data may be used.
The LRS needs to store all ‘voiding’ statements, and when returning statement results the LRS must filter out any statements which have been voided. The LRS should check to see if that statement made any changes to the activity or agent definitions and roll the changes that the statement made back. Read more about handling voided statements in the spec.
The LRS checks for syntax. It has to validate all of the pieces of a statement to make sure that data is formatted properly, required fields are present, and that the JSON values match the requirements of the spec. The semantics of a statement and meaning of the data within the statement is the responsibility of the activity provider.
Considering the volume of data that is flowing in and out of an LRS, concurrency is a major concern. The specification has many rules and checks that an LRS must do to make sure that the data in the LRS is not being degraded by putting old data into the LRS.
Signed statements have a special case in the LRS. They can be validated by the authority signing the statement without trusting the system that the statement originated in. In order for an LRS to validate signed statements, the LRS must check specific algorithms and properties in the JSON Web Signature (JWS) format. The implementor of the LRS needs to understand specification for JWS as well as the specific rules outlined in the xAPI specification.
An LRS returns only meta information only to HTTP headers, not the full documents in the LRS. A request can be made to find out if there is a newer version of a document without downloading the full document. This is a less load intensive way of checking to see if documents need to be downloaded from the LRS to support an application or report.
Future Proofing: API versioning and resource requests
Version headers are required in every response from an LRS to make it clear what versions of the xAPI specification the LRS supports. The version headers use semantic versioning. An LRS needs to provide an ‘about’ resource that returns JSON that identifies the versions of the specification that the LRS supports.
Handling the Past
There are three versions of the Experience API specification that are in use by different activity providers currently. The specification doesn’t require that an LRS support pre-release versions, but many LRS do. If the LRS does support version 0.9 and 0.95 of the spec, it needs to up-convert older versions to the most recent version of the specification so that they are able to be understood by all clients. This means that the older statements must be preserved in their original state and an updated version should be stored according to this appendix to the spec, appendix D.
Credential Management
An LRS is not required by the specification to do user management and permission management, but in order to be usable it will need to. This includes building ways for applications to register as OAuth consumers, managing user credentials, and managing basic authorization combos. Managing who can talk with the LRS is one part, the next step is to give controls for how much they can access which comes with a much more complicated set of decisions to be made about security and permissions.
Test your LRS with the Test Suite
There’s a basic xAPI conformance test suite that you can use to test how well your LRS conforms to the spec. It’s not complete, but it will test a wide range of things related to xAPI conformance. There’s no official “conformance certification” yet, so passing the test suite is the closest thing to an official certification. You can find the xAPI conformance test suite here.
Dealing with IE: Cross Origin Requests
The specification enables cross domain tracking, but the method for doing this does not allow HTTP headers to be set. This is a problem in using IE8 and IE9. There is a specific workaround for this in the specification that LRSs must support.
Beyond the basic, spec required LRS functionality:
Now, all of that said, if you want to build an LRS that is a standalone enterprise system it will need a lot more functionality. These are some of the things the LRS should do:
- Permissions management
- Push-pull statement synchronization with other lrs
- Data extraction, viewing and analysis
- Authentication management
- Actor merging, supported by the Agent API
Questions? Ask us anything.
At Rustici Software, we help hundreds of people each month with their xAPI questions. Many aren’t sales prospects; they just have questions. We’re happy to help. You can ask us anything ‒ really.