knitr::opts_chunk$set( eval = FALSE, comment = "#>", fig.path = "man/figures/README-", out.width = "100%" )
Learning Locker xAPI support for Shiny Applications.
xAPI [Experience API] is 100% free, open source, lightweight, and adaptable. It can be used to augment almost any performance assessment situation. It is being used in an expanding array of learning systems, from LMSs and simulator systems to museums and emergency medical services. – adlnet.gov
See also: What is the Experience API?
localhost
\/ 127.0.0.1
\/ RStudio's runApp()
are often blocked for this reason.You can install the released version of rLocker from GitHub with:
devtools::install_github("EducationShinyAppTeam/rLocker")
See the examples folder for demo code or visit psu-eberly.shinyapps.io/rLocker to see it in action.
Below are two approaches to creating and storing a simple xAPI statement in Learning Locker.
library(shiny) library(rLocker) shinyApp( server = function(input, output, session) { # Initialize Learning Locker connection -- substitute with your own locker credentials rLocker::connect(session, list( base_url = "https://learning-locker.example.com/", endpoint = "/data/xAPI/", auth = "Basic YWNjb3VudEBlbWFpbC5jb206c3VwZXJzZWNyZXRwYXNzd29yZA" )) # Register input event for interactive elements observeEvent(input$button, { statement <- rLocker::createStatement() rLocker::store(statement) }) } )
library(shiny) library(rLocker) shinyApp( ui = fluidPage( # Attach js logic tags$script(src = "js/app.js"), # Application title titlePanel("rLocker demo"), fluidRow( actionButton("button", "Press me!") ) ), server = function(input, output, session) { # Initialize Learning Locker connection -- substitute with your own locker credentials config <- jsonlite::toJSON( list( base_url = "https://learning-locker.example.com/", endpoint = "/data/xAPI/", auth = "Basic YWNjb3VudEBlbWFpbC5jb206c3VwZXJzZWNyZXRwYXNzd29yZA" ), pretty = TRUE, auto_unbox = TRUE, force = TRUE ) session$sendCustomMessage(type = 'rlocker-setup', config) # Register input events for interactive elements observeEvent(input$button, { session$sendCustomMessage(type = 'rlocker-store', rLocker::createStatement()) }) } )
Shiny.addCustomMessageHandler('rlocker-setup', function(config) { /* connection logic */ }); Shiny.addCustomMessageHandler('rlocker-store', function(values) { /* storage logic */ });
See adlnet/xAPIWrapper for JavaScript implementations.
Stored statements can be retreived from Learning Locker by using the retrieve
method.
Note: This requires a connection to be established by the R-handler to work; JS implementations can interface with the API through XMLHttpRequest instead.
response <- rLocker::retrieve( interface = "connection", model = "statement", query = "first=1", asJSON = TRUE ) print(response)
Response data can be returned as a JSON formatted string or as an R object (default). Below is sample output from the request above.
{ "edges": [ { "cursor": "eyJfaWQiOiI1YzQ2MmRiYjI0ZjVmMDRhOTI0MjZlMWMifQ==", "node": { "person": {}, "completedQueues": [], "processingQueues": [], "deadForwardingQueue": [], "pendingForwardingQueue": [], "completedForwardingQueue": [], "_id": "5c462dbb24f5f04a92426e1c", "hasGeneratedId": false, "organisation": "5c4383e369b9834b4e086caa", "lrs_id": "5c46260e85ce554a24b7579f", "client": "5c46260e85ce554a24b757a0", "active": true, "voided": false, "timestamp": "2019-01-21T20:38:19.131Z", "stored": "2019-01-21T20:38:19.131Z", "hash": "0905ec8aa05e67d247d7c888baf80b1f65c439c9", "agents": [ "886b382eb3a9570aeb3da9b34028a76ed761f1b9" ], "relatedAgents": [ "886b382eb3a9570aeb3da9b34028a76ed761f1b9", "mailto:hello@learninglocker.net" ], "registrations": [], "verbs": [ "http://adlnet.gov/expapi/verbs/launched" ], "activities": [ "http://127.0.0.1:4358/" ], "relatedActivities": [ "http://127.0.0.1:4358/" ], "statement": { "actor": { "objectType": "Agent", "name": "b5958c7b-22ba-404f-af7d-e5c3ccc6ddea", "mbox_sha1sum": "886b382eb3a9570aeb3da9b34028a76ed761f1b9" }, "verb": { "id": "http://adlnet.gov/expapi/verbs/launched", "display": { "en-US": "launched" } }, "object": { "objectType": "Activity", "id": "http://127.0.0.1:4358/", "definition": { "name": { "en-US": "rLocker demo" } } }, "id": "baa14dff-fbb2-4722-94a2-ecb268193436", "timestamp": "2019-01-21T20:38:19.131Z", "stored": "2019-01-21T20:38:19.131Z", "authority": { "objectType": "Agent", "name": "New Client", "mbox": "mailto:hello@learninglocker.net" }, "version": "1.0.0" }, "failedForwardingLog": [] } } ], "pageInfo": { "hasNextPage": true, "hasPreviousPage": false, "startCursor": "eyJfaWQiOiI1YzQ2MmRiYjI0ZjVmMDRhOTI0MjZlMWMifQ==", "endCursor": "eyJfaWQiOiI1YzQ2MmRiYjI0ZjVmMDRhOTI0MjZlMWMifQ==" } }
See HTTP Queries for more information on how to make calls to the records database.
|option|default| |---|---| |base_url|http://localhost:8000/xapi/| |endpoint|/data/xAPI/| |auth|Basic YWNjb3VudEBlbWFpbC5jb206c3VwZXJzZWNyZXRwYXNzd29yZA| |username|null| |password|null|
Note: base_url should be the hosting location for your locker's API without any endpoint or home.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.