- 0.2.1 - Update of Readme
- 0.2.0 - Initial commit and release to npm
ADL's Experience API wrapper for nodejs. The wrapper simplifies the process of communicating with an xAPI LRS.
Install the module with: npm install adl-xapiwrapper
Start the node Read-Eval-Print-Loop (REPL): node
or nodejs
depending on your installation.
See node's documentation for more information.
var adl = require('adl-xapiwrapper');
var opts = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
},
};
var mylrs = new adl.XAPIWrapper(opts);
mylrs.getStatements(null, null, function(err, resp, bdy) {
console.log(resp.statusCode);
console.log(JSON.parse(bdy));
});
>> 200
>> {statements:[..], more:""}
xapiversion
- the version of the Experience API Spec this conforms to
build
- an ISO date representing when this script was built
debugLevel
- the minimum logging level to process ['error','warn','info]
// these values will vary based on the version of wrapper you have
var adl = require('adl-xapiwrapper');
adl.xapiversion;
>> '1.0.1'
adl.build;
>> '2013-11-14T20:14Z'
adl.debugLevel;
>> 'warn'
function xapi_request(options, data, callback)
Encapsulates making requests to an LRS. See the section on this wrapper's
instance functions for scripted ways to make common
calls to an LRS. This uses the request module.
see requests
options
- options object used by the request module. see optionsdata
- the payload for POSTs and PUTscallback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
var adl = require('adl-xapiwrapper');
var myopts = {
"url":"https://lrs.adlnet.gov/xapi/statements",
"auth":{
"user":"tom",
"pass":"1234"
},
"method":"GET",
"qs":{
"limit":1
}
};
adl.debugLevel = 'info';
adl.xapi_request(myopts, null, function (error, response, body) {
adl.log('info', response.statusCode);
adl.log('info', body);
});
>> info: 200
>> info: {"statements": <statements>, "more": <more url>}
function hash(string)
Sha1 hash of a string. Used for hashing contents sent to
the document endpoints (state, activity profile, agent profile) to
use for concurrency checks.
var doc = "This is my activity profile";
var myhash = adl.hash(doc)
function log(level, message)
Writes message to console based on level. Levels are error
, warn
, info
.
Level filtering can be changed by setting adl.debugLevel
.
var adl = require('adl-xapiwrapper');
adl.debugLevel;
>> 'warn'
adl.log('info', 'this is an informational message');
> undefined
adl.debugLevel = 'info';
>> 'info'
adl.log('info', 'this is an informational message');
>> info: this is an informational message
function ruuid()
Generates a UUID that can be used anywhere the Experience API Spec
specifies one, such as Statement ID or Registration.
adl.ruuid();
>> '47df99dd-e75f-484d-a85b-78cc988ae7c7'
function dateFromISOString(isostring)
Converts an ISO date time string into a JavaScript date object.
var date = adl.dateFromISOString(adl.build);
date;
>> Thu Nov 14 2013 15:14:00 GMT-0500 (EST)
date.toDateString()
>> 'Thu Nov 14 2013'
function sendStatements(statements, callback)
Sends a single or a list of statements to the LRS.
Parameters:
statements
- the single statement as a JSON object, or list of statements as a JSON array of objectscallback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
var adl = require('adl-xapiwrapper');
adl.debugLevel = 'info';
var myconfig = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
}
};
var mylrs = new adl.XAPIWrapper(myconfig);
var stmt = {
"actor" : {"mbox" : "mailto:tom@example.com"},
"verb" : {"id" : "http://adlnet.gov/expapi/verbs/answered",
"display" : {"en-US" : "answered"}},
"object" : {"id" : "http://adlnet.gov/expapi/activities/question"}
};
mylrs.sendStatements(stmt, function (err, resp, bdy) {
adl.log('info', resp.statusCode);
adl.log('info', bdy);
});
>> info: 200
>> info: [<statement ids>]
function getStatements(searchparams, more, callback)
Retrieves a Statement Results
object from the LRS containing Statements that matched the search criteria and a possible URL in the
event more Statements exist that match the criteria.
Parameters:
searchparams
- JSON object of search parameters. See the xAPI Spec for parameters.more
- the url to more results.callback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
var adl = require('adl-xapiwrapper');
adl.debugLevel = 'info';
var myconfig = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
}
};
var mylrs = new adl.XAPIWrapper(myconfig);
mylrs.getStatements(null, null, function (err, resp, bdy) {
adl.log('info', resp.statusCode);
adl.log('info', bdy);
adl.log('info', JSON.parse(bdy).statements.length);
});
>> info: 200
>> info: {"statements":[<statements>], "more":<url to more results>}
>> info: 50 // depends on LRS
var adl = require('adl-xapiwrapper');
adl.debugLevel = 'info';
var myconfig = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
}
};
var mylrs = new adl.XAPIWrapper(myconfig);
mylrs.getStatements(null, null, function (err, resp, bdy) {
adl.log('info', resp.statusCode);
adl.log('info', bdy);
var bdyobj = JSON.parse(bdy)
if (bdyobj.more) {
adl.log('info', 'going to get more statements');
mylrs.getStatements(null, bdyobj.more, function (err, resp, bdy) {
adl.log('info', resp.statusCode);
adl.log('info', bdy);
});
}
});
>> info: 200
>> info: {"statements":[<statements>], "more":<url to more results>}
>> info: going to get more statements
>> info: 200
>> info: {"statements":[<statements>], "more":<url to more results>}
var adl = require('adl-xapiwrapper');
adl.debugLevel = 'info';
var myconfig = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
}
};
var mylrs = new adl.XAPIWrapper(myconfig);
var myopts = {"verb":"http://adlnet.gov/expapi/verbs/answered"};
mylrs.getStatements(myopts, null, function (err, resp, bdy) {
adl.log('info', resp.statusCode);
adl.log('info', bdy);
adl.log('info', JSON.parse(bdy).statements.length);
});
>> info: 200
>> info: {"statements":[<statements with verb 'answered'>], "more":<url to more results>}
>> info: 50 // depends on LRS
function getActivities(activityid, callback)
Gets the complete Activity
object from the LRS.
Parameters:
activityid
- the id of the Activity requestedcallback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
var adl = require('adl-xapiwrapper');
adl.debugLevel = 'info';
var myconfig = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
}
};
var mylrs = new adl.XAPIWrapper(myconfig);
mylrs.getActivities("act:adlnet.gov/JsTetris_XAPI", function (err, resp, bdy) {
adl.log('info', resp.statusCode);
adl.log('info', bdy);
});
>> info: 200
>> info: <complete Activity object>
function sendState(activityid, agent, stateid, registration, stateval, matchHash, noneMatchHash, callback)
Sends state information about the agent's experience of the activity.
Parameters:
activityid
- the id of the Activity this state is aboutagent
- the Agent this Activity state is related tostateid
- the id you want associated with this stateregistration
- (optional) the registraton id associated with this statestateval
- the statematchHash
- the hash of the state to replace or * to replace anynoneMatchHash
- the hash of the current state or * to indicate no previous statecallback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
function getState(activityid, agent, stateid, registration, since, callback)
Get activity state from the LRS
Parameters:
activityid
- the id of the Activity this state is aboutagent
- the Agent this Activity state is related tostateid
- (optional - if not included, the response will be a list of stateids associated with the activity and agent) the id you want associated with this stateregistration
- (optional) the registraton id associated with this statesince
- date object telling the LRS to return objects newer than the date suppliedcallback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
var adl = require('adl-xapiwrapper');
adl.debugLevel = 'info';
var myconfig = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
}
};
var mylrs = new adl.XAPIWrapper(myconfig);
var myactid = "http://example.com/activity/trails/appalachian";
var agent = {"mbox":"mailto:hikerbob@example.com"};
var mystateid = "training:appalachian-trail";
var mystate = {"trees":["hemlock","blue spruce"],"scene":"forest"};
mylrs.sendState(myactid, agent, mystateid, null, mystate, null, "*", function (err, resp, bdy) {
if (err) {
adl.log("error", "got an error");
} else {
adl.log("info", "response status: " + resp.statusCode);
}
});
>> info: response status: 204
mylrs.getState(myactid, agent, mystateid, null, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "got an error");
} else {
adl.log("info", "status code: " + resp.statusCode);
adl.log("info", "the state: " + bdy);
}
});
>> info: status code: 200
>> info: the state: {"trees":["hemlock","blue spruce"],"scene":"forest"}
var statehash = adl.hash(JSON.stringify(mystate));
mystate['checkpoint'] = "pa-w-blaze-6";
mylrs.sendState(myactid, agent, mystateid, null, mystate, statehash, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "got an error");
} else {
adl.log("info", "status code: " + resp.statusCode);
}
});
>> info: status code: 204
mylrs.getState(myactid, agent, mystateid, null, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "got an error");
} else {
adl.log("info", "state: " + bdy);
}
});
>> info: state: {"checkpoint": "pa-w-blaze-6", "scene": "forest", "trees": ["hemlock", "blue spruce"]}
mylrs.getState(myactid, agent, null, null, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "got an error");
} else {
adl.log("info", "state ids: " + bdy);
}
});
>> info: state ids: ["training:appalachian-trail"]
var sincehere = new Date()
var newstateid = "content:settings";
var newstate = {"fps":"30","resolution":"1680x1050"};
mylrs.sendState(myactid, agent, newstateid, null, newstate, null, "*", function (err, resp, bdy) {
if (err) {
adl.log("error", "error with request: " + err);
} else {
adl.log("info", "status: " + resp.statusCode);
}
});
>> info: status: 204
// get all state ids
mylrs.getState(myactid, agent, null, null, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "error with request: " + err);
} else {
adl.log("info", "state ids: " + bdy);
}
});
>> info: state ids: ["content:settings", "training:appalachian-trail"]
// get ids of states saved since ..
mylrs.getState(myactid, agent, null, null, sincehere, function (err, resp, bdy) {
if (err) {
adl.log("error", "error with request: " + err);
} else {
adl.log("info", "state ids since " + sincehere + ": " + bdy);
}
});
>> info: state ids since Mon Nov 18 2013 09:31:15 GMT-0500 (EST): ["content:settings"]
function sendActivityProfile(activityid, profileid, profileval, matchHash, noneMatchHash, callback)
Sends an Activity Profile to the LRS.
Parameters:
activityid
- the id of the Activity this profile is aboutprofileid
- the id you want associated with this profileprofileval
- the profilematchHash
- the hash of the profile to replace or * to replace anynoneMatchHash
- the hash of the current profile or * to indicate no previous profilecallback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
function getActivityProfile(activityid, profileid, since, callback)
Get activity profile from the LRS
Parameters:
activityid
- the id of the Activity this profile is aboutprofileid
- (optional - if not included, the response will be a list of profileids associated with the Activity) the id of the profilesince
- date object telling the LRS to return objects newer than the date suppliedcallback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
var adl = require('adl-xapiwrapper');
adl.debugLevel = 'info';
var myconfig = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
}
};
var mylrs = new adl.XAPIWrapper(myconfig);
var profile = {"type":"question"};
var activityid = "http://adlnet.gov/expapi/activities/question";
var profileid = "question:profile";
mylrs.sendActivityProfile(activityid, profileid, profile, null, "*", function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "status: " + resp.statusCode);
}
});
>> info: status: 204
mylrs.getActivityProfile(activityid, profileid, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile: " + bdy);
}
});
>> info: profile: {"type":"question"}
var profhash = adl.hash(JSON.stringify(profile));
profile["updated"] = true;
mylrs.sendActivityProfile(activityid, profileid, profile, profhash, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "status: " + resp.statusCode);
}
});
>> info: status: 204
mylrs.getActivityProfile(activityid, profileid, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile: " + bdy);
}
});
>> info: profile: {"updated": true, "type": "question"}
mylrs.getActivityProfile(activityid, null, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile ids: " + bdy);
}
});
>> info: profile ids: ["question:profile"]
var sincehere = new Date();
var newprofile = {"another" : "profile"};
var newprofileid = "another:profile";
mylrs.sendActivityProfile(activityid, newprofileid, newprofile, null, "*", function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "status: " + resp.statusCode);
}
});
>> info: status: 204
// get all ids
mylrs.getActivityProfile(activityid, null, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile ids: " + bdy);
}
});
>> info: profile ids: ["question:profile", "another:profile"]
// get ids of Activity Profiles saved since date...
mylrs.getActivityProfile(activityid, null, sincehere, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile ids: " + bdy);
}
});
>> info: profile ids: ["another:profile"]
function getAgents(agent, callback)
Gets a special Person object containing all the values
of an Agent the LRS knows about. The Person object's
identifying properties are arrays and it may have more
than one identifier. See more about Person in the spec
Parameters:
agent
- JSON object representing an Agent ex: {"mbox":"mailto:tom@example.com"}callback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
var adl = require('adl-xapiwrapper');
adl.debugLevel = 'info';
var myconfig = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
}
};
var mylrs = new adl.XAPIWrapper(myconfig);
mylrs.getAgents({"mbox":"mailto:tom@example.com"}, function (err, resp, bdy) {
if (err) {
adl.log("error", "error in request: " + err);
} else {
adl.log("info", "the Person: " + bdy);
}
});
>> info: the Person: <Person object>
function sendAgentProfile(agent, profileid, profileval, matchHash, noneMatchHash, callback)
Sends an Agent Profile to the LRS.
Parameters:
agent
- the Agent this profile is related toprofileid
- the id you want associated with this profileprofileval
- the profilematchHash
- the hash of the profile to replace or * to replace anynoneMatchHash
- the hash of the current profile or * to indicate no previous profilecallback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
function getAgentProfile(agent, profileid, since, callback)
Gets an Agent Profile from the LRS.
Parameters:
agent
- the Agent associated with this profileprofileid
- (optional - if not included, the response will be a list of profileids associated with the agent) the id of the profilesince
- date object telling the LRS to return objects newer than the date suppliedcallback
- function to process after request has completed.- Parameters passed to callback:
error
- an error message if something went wrongresponse
- the response objectbody
- the body of the response if there is one
var adl = require('adl-xapiwrapper');
adl.debugLevel = 'info';
var myconfig = {
"url":"https://lrs.adlnet.gov/xapi/",
"auth":{
"user":"tom",
"pass":"1234"
}
};
var mylrs = new adl.XAPIWrapper(myconfig);
var profile = {"competencies":["http://adlnet.gov/competency/sitting-quietly",
"http://adlnet.gov/competency/watching-tv"],
"current path":"http://adlnet.gov/competency/knitting"};
var agent = {"mbox":"mailto:tom@example.com"};
var profileid = "competencies";
mylrs.sendAgentProfile(agent, profileid, profile, null, "*", function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "status: " + resp.statusCode);
}
});
>> info: status: 204
mylrs.getAgentProfile(agent, profileid, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile: " + bdy);
}
});
>> info: profile: {"competencies":["http://adlnet.gov/competency/sitting-quietly",
"http://adlnet.gov/competency/watching-tv"],
"current path":"http://adlnet.gov/competency/knitting"}
var profhash = adl.hash(JSON.stringify(profile));
profile["competencies"].push(profile['current path']);
profile["current path"] = "http://adlnet.gov/competency/juggling";
mylrs.sendAgentProfile(agent, profileid, profile, profhash, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "status: " + resp.statusCode);
}
});
>> info: status: 204
mylrs.getAgentProfile(agent, profileid, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile: " + bdy);
}
});
>> info: profile: {"competencies": ["http://adlnet.gov/competency/sitting-quietly",
"http://adlnet.gov/competency/watching-tv",
"http://adlnet.gov/competency/knitting"],
"current path": "http://adlnet.gov/competency/juggling"}
mylrs.getAgentProfile(agent, null, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile ids: " + bdy);
}
});
>> info: profile ids: ["competencies"]
var sincehere = new Date();
var newprofile = {"another" : "profile"};
var newprofileid = "another:profile";
mylrs.sendAgentProfile(agent, newprofileid, newprofile, null, "*", function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "status: " + resp.statusCode);
}
});
>> info: status: 204
// get all ids
mylrs.getAgentProfile(agent, null, null, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile ids: " + bdy);
}
});
>> info: profile ids: ["competencies", "another:profile"]
// get ids of Activity Profiles saved since date...
mylrs.getAgentProfile(agent, null, sincehere, function (err, resp, bdy) {
if (err) {
adl.log("error", "request error: " + err);
} else {
adl.log("info", "profile ids: " + bdy);
}
});
>> info: profile ids: ["another:profile"]
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using Grunt.
We welcome contributions to this project. Fork this repository, make changes, and submit pull requests. If you're not comfortable with editing the code, please submit an issue and we'll be happy to address it.
Copyright ©2016 Advanced Distributed Learning
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.