Skip to main content

Crate xapi_rs

Crate xapi_rs 

Source
Expand description

HTTP Server implementation of xAPI 2.0.0 LRS.

In earlier versions, there were 3 main modules in this project that covered:

  1. data – the data structures involved.
  2. db – their Data Access Objects for storing in, and fetching them from a database, and finally
  3. lrs – 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:

  1. Deserialization and Serialization:

    • serde: for the basic serialization + deserialization capabilities.
    • serde_json: for the JSON format bindings.
    • serde_with: for custom helpers.
  2. IRL1, IRI2, URI3 and URL4:

    • iri-string: for IRIs and URIs incl. support for serde
    • url: for Uniform Resource Locators.
  3. UUID5:

    • uuid: for handling generating, parsing and formatting UUIDs.
  4. Date, Time and Durations:

    • chrono: for timezone-aware date and time handling.
    • speedate: for fast and simple duration6 parsing.
  5. 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.
  6. Email Address:

  7. Semantic Version:

  8. Case Insensitive Strings:

    • unicase: for comparing strings when case is not important (using Unicode Case-folding).
  9. JWS signatures:

    • josekit: for creating + validating JWS signed Statements.
    • openssl: for handling X.509 certificates when included in JWS Headers.

§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:

PropertyTypeDescriptionRequired
nameStringFull name of the Agent.No
mboxmailto IRIEmail address.[7]
mbox_sha1sumStringThe hex-encoded SHA1 hash of mbox.[7]
openidURIAn openID that uniquely identifies the Agent.[7]
accountObjectA user account and username pair.[7]

While an Identified Group has the following properties:

PropertyTypeDescriptionRequired
nameStringName of the Group.No
mboxmailto IRIEmail address.[7]
mbox_sha1sumStringThe hex-encoded SHA1 hash of mbox.[7]
openidURIAn openID that uniquely identifies the Group.[7]
accountObjectA user account and username pair.[7]
memberArray of Agent objectsUnordered list of group’s membersNo

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 mbox in xAPI parlance). Note we only store the email address proper w/o the mailto scheme.
  • 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_page URL, a ‘~’ symbol followed by a name (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:

PropertyTypeDescription
nameArray of StringsList of names.
mboxArray of IRIsList of Email addresses.
mbox_sha1sumArray of StringsList of hashes.
openidArray of URIsList of openIDs
accountArray of ObjectsList 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 GET request adds an ETag HTTP header to the response.
  • LaRS responding to a PUT, POST, or DELETE request handles the If-Match header as described in RFC2616, HTTP 1.1 in 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 PUT request which includes an If-None-Match header field with the same etag as was used in the If-match header field in the first PUT request, or
  • If not known, issue a new PUT request which includes an If-Match with the etag of the existing resource on the server (this etag being the one recieved in the response to the initial HEAD request). This could also have been achieved by resubmitting the PUT request without a precondition. However, the advantage of using the precondition is that the server can block all PUT requests without any preconditions as such requests are guaranteed to come from old clients without knowledge of etags and preconditions.

  1. IRL: Internationalized Resource Locator. 

  2. IRI: Internationalized Resource Identifier. 

  3. URI: Uniform Resource Identifier. 

  4. URL: Uniform Resource Locator. 

  5. UUID: Universally Unique Identifier –see https://en.wikipedia.org/wiki/Universally_unique_identifier

  6. Durations in ISO 8601:2004(E) sections 4.4.3.2 and 4.4.3.3. 

  7. Exactly One of mbox, mbox_sha1sum, openid, account is required. ↩ 1 2 3 4 5 6 7 8

  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 $err at level error before returning it.
emit_response
Given $resource of type $type that is serde Serializable 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 the If-XXX pre- 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 RowNotFound error.
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-Through HTTP header name.
CONTENT_TRANSFER_ENCODING_HDR
The Content-Transfer-Encoding HTTP 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-Hash HTTP 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-Version HTTP header name.

Functions§

build
Entry point for constructing a Local Rocket and use it for either testing or not. When testing is TRUE a mock DB is injected otherwise it’s the real McKoy.
config
This LRS server configuration Singleton.