Expand description
HTTP Server implementation of xAPI 2.0.0 LRS.
In earlier versions, there were 3 main modules in this project that covered:
data– the data structures involved.db– their Data Access Objects for storing in, and fetching them from a database, and finallylrs– a Web server to handle the LRS calls proper.
The first is now a separate crate w/ its own version, published as xapi-data. Separating
the rest is still a work-in-progress. For now LaRS (the LRS server proper) is effectively
the server member of the Workspace (still) published as xapi-rs.
§Third-party crates
This server depends on few best-of-breed libraries to achieve correct compliance w/ other IETF and ISO standards referenced in xAPI.
Here’s a list of the most important ones:
-
Deserialization and Serialization:
- serde: for the basic serialization + deserialization capabilities.
- serde_json: for the JSON format bindings.
- serde_with: for custom helpers.
-
- iri-string: for IRIs and URIs incl. support for serde
- url: for Uniform Resource Locators.
-
UUID5:
- uuid: for handling generating, parsing and formatting UUIDs.
-
Date, Time and Durations:
-
Language Tags and MIME types:
- language-tags: for parsing , formatting and comparing language tags as specified in BCP 47.
- mime: for support of MIME types (a.k.a. Media Types) when dealing w/ Attachments.
-
Email Address:
- email_address: for parsing and validating email addresses.
-
Semantic Version:
- semver: for semantic version parsing and generation as per Semantic Versioning 2.0.0.
-
Case Insensitive Strings:
- unicase: for comparing strings when case is not important (using Unicode Case-folding).
-
JWS signatures:
§db - Persistent Storage
This module deals w/ storing, mutating and retrieving database records representing the concrete data.
It does not hide the database engine and SQL dialect it uses for achieving its purpose. PostgreSQL is the relational database engine used. When this page was last updated the PosgreSQL version in use was 18.3.
§A note about how Agents, Groups and Actors are stored in the database
xAPI describes an Actor as “…Agent or Identified Group object (JSON)”. An Agent has the following properties:
| Property | Type | Description | Required |
|---|---|---|---|
name | String | Full name of the Agent. | No |
mbox | mailto IRI | Email address. | [7] |
mbox_sha1sum | String | The hex-encoded SHA1 hash of mbox. | [7] |
openid | URI | An openID that uniquely identifies the Agent. | [7] |
account | Object | A user account and username pair. | [7] |
While an Identified Group has the following properties:
| Property | Type | Description | Required |
|---|---|---|---|
name | String | Name of the Group. | No |
mbox | mailto IRI | Email address. | [7] |
mbox_sha1sum | String | The hex-encoded SHA1 hash of mbox. | [7] |
openid | URI | An openID that uniquely identifies the Group. | [7] |
account | Object | A user account and username pair. | [7] |
member | Array of Agent objects | Unordered list of group’s members | No |
Those mbox, mbox_sha1sum, openid, and account properties are also referred to as Inverse Functional Identifier (IFI for short). The Kind of IFI is encoded as an integer:
- 0 -> email address (or
mboxin xAPI parlance). Note we only store the email address proper w/o themailtoscheme. - 1 -> hex-encoded SHA1 hash of a mailto IRI; i.e. 40-character string.
- 2 -> OpenID URI identifying the owner.
- 3 -> account on an existing system stored as a single string by concatenating the
home_pageURL, a ‘~’ symbol followed by aname(the username of the account holder).
We store this information in two tables: one for the IFI data proper, and another for the association of Actors to their IFIs.
§A note about the relation between an Agent and a Person
Worth noting also that one of the REST endpoints of the LRS (see section 4.1.6.3 Agents resource) is expected, given an Agent instance, to retrieve a special Person object with combined information about an Agent derived from an outside service?!.
This Person object is very similar to an Agent, but instead of each attribute having a single value, it has an array of them. Also it’s OK to include multiple identifying properties. Here’s a table of those Person’s properties:
| Property | Type | Description |
|---|---|---|
name | Array of Strings | List of names. |
mbox | Array of IRIs | List of Email addresses. |
mbox_sha1sum | Array of Strings | List of hashes. |
openid | Array of URIs | List of openIDs |
account | Array of Objects | List of Accounts. |
It’s important to note here that while xAPI expects the LRS to access an external source of information to collect an Agent’s possible multiple names and IFIs –in order to aggregate them to build a Person– it is silent as to how a same Agent being identified by its single IFI ends up having multiple ones of the same or different Kinds. In addition if the single IFI that identifies an Agent w/ respect to the REST Resources is not enough to uniquely identify it, how are multiple Agent persona 8 connected? do they share a primary key? which Authority assigns such key? and how is that information recorded / accessed by the LRS?
Until those points are resolved, this LRS considers a Person to be an Agent and vice-versa.
§lrs - LRS Web Server
This module, nicknamed LaRS, consists of the Learning Record Store (LRS) —a web server– that allows access from Learning Record Providers (LRPs), or Consumers (LRCs).
§Concurrency
Concurrency control makes certain that a PUT, POST or DELETE does not perform operations based on stale data.
§Details
In accordance w/ xAPI, LaRS uses HTTP 1.1 entity tags (ETags) to implement optimistic concurrency control in the following resources, where PUT, POST or DELETE are allowed to overwrite or remove existing data:
- State Resource
- Agent Profile Resource
- Activity Profile Resource
§Requirements
- LaRS responding to a
GETrequest adds an ETag HTTP header to the response. - LaRS responding to a
PUT,POST, orDELETErequest handles the If-Match header as described inRFC2616, HTTP 1.1in order to detect modifications made after the document was last fetched.
If the preconditions in the request fails, LaRS:
- returns HTTP status
412 Precondition Failed. - does not modify the resource.
If a PUT request is received without either header for a resource that already exists, LaRS:
- returns HTTP status
409 Conflict. - does not modify the resource.
§Detecting the Lost Update problem using unreserved checkout
When a conflict is detected, either because a precondition fails or a HEAD request indicated a resource already exists, some implementations offer the user two choices:
- download the latest revision from the server so that the user can merge using some independent mechanism; or
- override the existing version on the server with the client’s copy.
If the user wants to override the existing revision on the server, a 2nd PUT request is issued. Depending on whether the document initially was known to exist or not, the client may either…
- If known to exist, issue a new
PUTrequest which includes anIf-None-Matchheader field with the same etag as was used in theIf-matchheader field in the firstPUTrequest, or - If not known, issue a new
PUTrequest which includes anIf-Matchwith the etag of the existing resource on the server (this etag being the one recieved in the response to the initialHEADrequest). This could also have been achieved by resubmitting thePUTrequest without a precondition. However, the advantage of using the precondition is that the server can block allPUTrequests without any preconditions as such requests are guaranteed to come from old clients without knowledge of etags and preconditions.
IRL: Internationalized Resource Locator. ↩
IRI: Internationalized Resource Identifier. ↩
URI: Uniform Resource Identifier. ↩
URL: Uniform Resource Locator. ↩
UUID: Universally Unique Identifier –see https://en.wikipedia.org/wiki/Universally_unique_identifier. ↩
Durations in ISO 8601:2004(E) sections 4.4.3.2 and 4.4.3.3. ↩
Exactly One of mbox, mbox_sha1sum, openid, account is required. ↩ 1 2 3 4 5 6 7 8
Person in that same section 4.1.6.3 is being used to indicate a person-centric view of the LRS Agent data, but Agents just refer to one persona (a person in one context). ↩
Modules§
- resources
- Endpoints grouped by Resource.
Macros§
- constraint_
violation_ error - Generate a message (in the style of
format!macro), log it at level error and raise a data constraint violation error. - emit_
db_ error - Macro for logging and wrapping database errors before returning them as ours.
- emit_
error - Log
$errat level error before returning it. - emit_
response - Given
$resourceof type$typethat isserdeSerializable and$headers(an instance of a type that handles HTTP request headers)… - eval_
preconditions - Given an
$etag(Entity Tag) value and$headers(an instance of a type that handles HTTP request headers), check that theIf-XXXpre- conditions when present, pass. - handle_
db_ error - Macro for logging and handling errors with a custom return value to use
when the database raises a
RowNotFounderror. - runtime_
error - Generate a message (in the style of
format!macro), log it at level error and raise a runtime error.
Structs§
- Aggregates
- Structure used when computing SQL Aggregates suitable for use by a client’s pagination mechanism.
- Config
- A structure that provides the current configuration settings.
- User
- Representation of a user that is subject to authentication and authorization.
- VerbUI
- Simplified Verb representation.
Enums§
- Mode
- Modes of operations of this LRS.
- MyError
- Enumeration of different error types raised by this crate.
- Role
- Authorization role variants.
Constants§
- CONSISTENT_
THRU_ HDR - The xAPI specific
X-Experience-API-Consistent-ThroughHTTP header name. - CONTENT_
TRANSFER_ ENCODING_ HDR - The
Content-Transfer-EncodingHTTP header name. - EXT_
STATS - Statistics/Metrics Extension IRI
- EXT_
USERS - User Management Extension IRI
- EXT_
VERBS - Verbs Extension IRI
- HASH_
HDR - The xAPI specific
X-Experience-API-HashHTTP header name. - STATS_
EXT_ BASE - Statistics Extension base URI.
- TEST_
USER_ PLAIN_ TOKEN - The pre base-64 encoded input for generating test user credentials and populating HTTP Authorization header.
- USERS_
EXT_ BASE - Users Extension base URI.
- V200
- The xAPI version this project supports by default.
- VERBS_
EXT_ BASE - Vebrs Extension base URI.
- VERSION_
HDR - The xAPI specific
X-Experience-API-VersionHTTP header name.