Javascript API Sample

This is a complete script demonstrating interaction with the main Web API calls to scrambls.

/**
 * apiKey:  the UUID doled out by Wave
 */
var apiKey = "put API key in here";
/**
 * constants defined by the HTTP API
 */
var httpHdrAuth = "x-xloak-authtoken";
var httpHdrKey = "x-xloak-k";
var httpHdrClient = "x-xloak-cli";
/**
 * hpBase is the "host/protocol" base URL that is common to all APIs
 */
var hpBase = "https://scrambls.com";
/**
 * "api" just lists the HTTP APIs available to clients in a convenient object.
 */
var api = {uAccount:  hpBase + "/upi/account",
           uAuth:     hpBase + "/upi/auth",
           aUserPS:   hpBase + "/api/userps",
           aXContent: hpBase + "/api/xcontent"
          };
/**
 * For running in a browser window, just make the debug output bring up a dialog
 */
function DEBUG(s) {
   window.alert(s);
}
/**
 * xhrCall is a generic function to make a call to the server and invoke one of
 * two functions once the returned data is received.
 *
 * Parameters:
 *  api:    full URL; if non-POST, then must include params; pull from "api" object
 *  data:   if defined, then API call is assumed to be POST operation; object; JSON object
 *  at:     a valid auth token
 *  ok:     function to call on 200 code; sig is function(parsedJSON)
 *  fail:   function to call on non-200 code; sig is function(code)
 *  method: required if not GET or POST
 */
function xhrCall(api, data, ata, ok, fail, method) {
    var req = new XMLHttpRequest();
    var type;
   // if we're sending data, then declare it to be of type application/json
   // and make the method POST, unless overridden by caller
    if (data) {
        data = JSON.stringify(data);
        type = "application/json";
        if (!method)
            method = "POST";
    }
   // default to HTTP GET method
    if (!method)
        method = "GET";
    req.open(method, api, true);   // "true" -> asynchronous call
   // all API calls require a valid API key
    req.setRequestHeader(httpHdrKey, apiKey);
   // authenticated API calls require an auth token, so put it in the HTTP header area
    if (ata) {
        req.setRequestHeader(httpHdrAuth, ata);
    }
   // API calls that transmit data require the Content-Type header
    if (type) {
        req.setRequestHeader("Content-type", type);
    }
   // set up for asynchronous callback:
    req.onreadystatechange = function (evt) {
        if (req.readyState == 4) {
            if (req.status == 200) {
                var resp = JSON.parse(req.responseText);  // format:  {status:ok, info:{blah:blah, ...}}
//                DEBUG(api + " got back SC=200:  " + req.responseText);
                if (ok)
                    ok(resp);
            }
            else {
                var resp;
//                DEBUG(api + " got back SC=" + req.status + ", resp = " + req.responseText + ", Content-Type header = " + req.getResponseHeader("Content-Type"));
                if (req.responseText) {
                    resp = JSON.parse(req.responseText);  // format:  {blah:blah, ...}
                }
                if (fail) {
                    fail(req.status, resp);
                }
            }
        }
    }
   // actually make the API call
    req.send(data);
}
// Beginning of sample API calls
// getXIDInfo returns information about an XID if the caller has permission to access it
function getXIDInfo(authToken, xid) {
   // accessing information about an XID requires that we tell the server where the access
   // is.
   var url = ";
   xhrCall((api.aXContent + "/" + xid + "?url=" + escape(url)), null, authToken,
         function(resp) {
            DEBUG("XID Info:  " + JSON.stringify(resp.info));
         },
         function(code, resp) {
            DEBUG("failed to get XID info; code = " + code + ", " + JSON.stringify(resp));
         });
}
// createXID creates an XID; it uses the first policy in the list of user policies.
function createXID(authToken, policies) {
   // creating an XID requires that we tell the server where the posted content will live
   var url = ";
   // creating an XID requires that the client pass the key.  this key
   // is the hexadecimal encoding of an arbitrary length array of bytes
   // so this will be a string of even length.
   var key = "00112233ddeeff";
   // xpid is the policy ID that the XID will use for access control.  It must
   // be obtained by choosing one of the policies in the user's list of policies.
   var xpid = policies[0].xpid;
   // scheme gives information about how the client will be ciphering/encrypting the
   // data.  Currently only "default" is supported.
   var scheme = policies[0].cipherscheme;
   // make the actual call
   xhrCall(api.aXContent, {xpid: xpid, scheme: scheme, url: url, key: key}, authToken,
         function(resp) {
            DEBUG("Created XID:  " + JSON.stringify(resp.info));
            getXIDInfo(authToken, resp.info.xid);
         },
         function(code, resp) {
            DEBUG("failed to create XID; code = " + code + ", " + JSON.stringify(resp));
         });
}
// starts the chain of (asynchronous) tests by getting the user policies
function afterAuth(authToken) {
   // make a call to get the user's list of policies.  when we get that list
   // make the call to create an XID
   xhrCall(api.aUserPS, null, authToken,
         function(resp) {
            DEBUG("User policies:  " + JSON.stringify(resp.info));
            createXID(authToken, resp.info);
         },
         function(code, resp) {
            DEBUG("failed to get user policies; code = " + code + ", " + JSON.stringify(resp));
         });
}
// authenticates against the server and on successful authentication gets the
// rest of the tests running.  The important outcome of the authentication
// is the auth token, as all authenticated APIs require that.
function authTest(after) {
   // authentication requires email address and password of a valid account
   xhrCall(api.uAuth, {'email':'put in account email address', 'password':'put in account password'}, null,
         function(resp) {
//            DEBUG("got response " + JSON.stringify(resp));
            // resp.result should ALWAYS be "OK"
            after(resp.info.authToken);
         },
         function(code, resp) {
            DEBUG("auth failed with code " + code + ":  " + JSON.stringify(resp));
         });
}
// entry point for the onload event handler
function runtest() {
   authTest(afterAuth);
}