Learn how to use the cloud functions of the Kotobee Reader API. For advanced users.

When building scalable ebook apps using the Kotobee Reader API, you will find the API cloud functions very useful. These include setData, getData, getDataArray to store persistent data for the user on the cloud. Let's take a practical scenario to see how useful this can be.

For the Reader API's cloud functions to work, the user must be logged in to a cloud ebook or library. Otherwise, an error will be thrown.

Say you'd like to include a button at the end of each chapter labeled "I have completed this chapter". If the user clicks on that button, the label will be toggled to "Completed!". Regardless of which device the user opens the ebook at, as along as he logs into his same account, he should see the same label for each button. Not just that, but at the first chapter of the ebook, the user will see a list of all the chapters that still haven't been marked as complete. As tricky as it sounds, it's quite simple really.

Setting Data

When the user clicks on the completion button, we want to set some data for that user on the cloud, to mark that this chapter has been completed. This is where the setData function is extremely helpful. To use it, we will pass the following object.

{label: 'chapter 1', data: true, overwrite: true}

The second parameter is a callback that will be called once the setData request is complete. The data (i.e. true) passed in the object above, should take the current state of the button into consideration. If the button is already clicked, then data would be false instead. The overwrite variable is important to keep just one unique label in the database, instead of saving an array of them.

Here is a more comprehensive code block to show you what it should look like in your global JS.

completionBtn.addEventListener("click", function(event){
    completionBtn.classList.add("processing");
    var alreadyComplete = completionBtn.classList.has("complete");
    kotobee.setData({label:'chapter 1', data:!alreadyComplete, overwrite:true}, function(){
        if(!alreadyComplete)
             completionBtn.classList.remove("complete");
        else
             completionBtn.classList.add("complete");
        completionBtn.classList.remove("processing");
        kotobee.popup("Complete!");
   });
});

Getting Data

Once any chapter is opened, it is unknown whether this chapter has been marked as complete or not. So a request is needed to find that out. The getData function he will serve this purpose. It is structured similarly to the setData function. For the passed object in our case, it will take a single variable:

{label: 'chapter 1'}

The callback will return an array of data for that particular label. Since we have set overwrite to true when setting the data, the returned array will contain at most a single entry. 

Note that in this example it's straightforward, but if you're building more complex ebook apps, you may want to utilize the category and subcategory variables, to better structure your data. The more structured the data is, the easier it will be to make queries using getData.

The code block in the global JS will look like this:

kotobee.getData({label: 'chapter 1'}, function(resultArray){
     if(!resultArray.length) return;
     var result= resultArray[0];
     if(result.data) 
        completionBtn.classList.add("complete");
    else
        completionBtn.classList.remove("complete");
});

Getting Multiple Data

So the previous code block will get the data labeled 'chapter 1' for the currently logged in user and based on the returned value will either add or remove the "complete" class to a button. That same code block may be used in a separate chapter to display a listing of all the chapters that have not yet been marked as complete. Instead of making a separate request for each chapter (i.e. calling getData multiple times) we can make a single request using the getDataArray function. This consolidates multiple getData requests into one, all under a single request to optimize speed. It will look like this:

var array = [
  {label: 'chapter 1', id:'ch1'},
  {label: 'chapter 2', id:'ch2'},
  {label: 'chapter 3', id:'ch3'},
  {label: 'chapter 4', id:'ch4'},
  {label: 'chapter 5', id:'ch5'},
  {label: 'chapter 6', id:'ch6'}
]
kotobee.getDataArray(array, function(resultArray){
    console.log(resultArray);
});

The purpose of the passed id variables in the array is to label each item result of the return result array, In our case it doesn't make much sense since the label already has sufficient meaning to use an an id, but in most other cases an id will need to be used.

Getting Data from All Users

Here is where lies the power of the Kotobee Reader API. Now say you want for a particular user of the same ebook, to see a listing of all the completed chapters for all the users. So he's not just seeing his own completed chapters, but can see a complete listing of every single user using that same ebook, and which chapters each user has completed.

No users have permissions to do that. But you can give such a permission to users of your choice. This is done through the Add global data access button in the Permissions dialog in Kotobee Author:

Users who global data access permissions have the following privileges:

  • Can use the getUsers function to get a list of all registered users in the ebook or library.
  • Can pass the "allUsers" variable when calling getData, to query that data across all user accounts, not just his.

For best practice, it's best to create a user role (e.g. named Administrator, or Instructor) and provide global data access to that user role. This way it's easy to manage users that have such a privilege.