Accessing APIs via JavaScript

Jump to solution
sepehr_malek
Community Participant

Hello,

We are designing a page with a few buttons linked to different pages within a course. We want the buttons to only appear when the pages they are linked to are published.

The way I'm trying to achieve this is to access the APIs with the custom javascript and check if the page is published or not. I've done some testing with the code bellow:

$.getJSON("/api/v1/courses/:courseID/pages", function(data) { x = data; });

      for (i in x) {

                        console.log(x[i]["title"] + " - " + x[i]["published"]);

}

The problem is when I login as the student, this code wont show me any results which I think its because the student account doesn't have access to unpublished pages. Which means I have to call the APIs with an access token which I do not want to put in the custom javascript.

When I run the script above in my own account (admin), I get the result I need, though, it only show me 10 item in the results. I have more than 10 pages in the course.

I'd really appreciate some insight if anyone can help.

Thanks,

Sepehr

1 Solution
James
Community Champion

 @sepehr_malek ,

Definitely, do not, under any circumstances, make the code that has your access code in it available through JavaScript or anywhere else that people can access it. JavaScript is not secure and anyone that runs your script can go into the developer tools on the browser and get your access token then become you -- the administrator.


The issue of only having 10 pages show up is because of pagination that the API uses. By default, most API calls only return 10 items and then you have to load additional ones by looking at the Link headers. You can increase the 10 by specifying a query parameter of per_page, where you can have up to 100 items returned at a time for most things. That might be enough, or you may outgrow it and still have to use pagination.

The JavaScript you have doesn't seem right. You assign x inside of the function from the jQuery getJSON call, but the part that operates on it is outside of the function. Because of the asynchronous nature of JavaScript and AJAX calls, either there is some code missing or you are really lucky that it even knows what x is and you're getting anything. If there isn't anything else there, then it may be that it's cached for you, but when you logged in as the student, it didn't have the results cached so it wasn't showing anything at all, not just the published ones.

Here's what I see when I look at your code. The for loop should execute before the jquery.getJSON() returns.

$.getJSON("/api/v1/courses/:courseID/pages", function(data) {
  x = data;
});
for (i in x) {
  console.log(x[i]["title"] + " - " + x[i]["published"]);
}

Instead, you might want something like this. It doesn't handle pagination, though, so if you go over 100 pages, you'll have to worry about that as well. It also checks to see that you're within a course context, but that check probably won't work on mobile.  It returns a list of all pages with true or false for the instructor and just the published pages and true for a student.

(function() {
  'use strict';
  var pathRegex = new RegExp('^/courses/([0-9]+)/?');
  var matches = pathRegex.exec(window.location.pathname);
  if (matches) {
    var courseId = matches[1];
    $.getJSON('/api/v1/courses/' + courseId + '/pages?per_page=100', function(data) {
      for (var i = 0; i < data.length; i++) {
        console.log(data[i].title + ' - ' + data[i].published);
      }
    });
  }
})();

If you're just trying to see what values were returned, then just console.log(x) rather than using the for ... in construct. The for ... in construct does not guarantee the values will be returned in order. That may not be important when you're just dumping them or if you just need to iterate through them, but it may not be what you want when it comes time to display them. I never use for ... in with arrays, so that's why I changed my code, use what you need to use, but be sure to declare the variables so you don't clobber any global variable that might be named i or x.

I'm trying to wrap my head around what you're wanting to accomplish.

We want the buttons to only appear when the pages they are linked to are published.

I can think of several ways to interpret that and the solution might depend on which one you want.

  • You automatically generate a list of all pages in a course and want buttons to appear next to the ones that are published without buttons on the ones that are not published
  • You have a predefined list of certain pages in a course and you want to list all of the pages but only want buttons to appear next to the ones that are published while no buttons appear next to the ones that are not published
  • You want to automatically generate a list of pages that someone can see and add buttons next to them
  • You have a predefined list of certain pages and you only want those that are published to show and have buttons next to them as well

If you're talking about the first one, then you're not going to be able to do that from the student's login with just Canvas. The students can only see the pages that are available to them and even if the page is published, they still may not be able to access it because of module prerequisites. What you might be able to do is offload the processing to a script on a server you maintain. There your script would call the API using your credentials, but because it's server side instead of client side, then you aren't as worried about the credentials getting out. In that script, you process whatever needs processed and send the information back to Canvas. You might want to do some short-term caching to minimize the number of calls that are made to the API and the delay of calling the one script that then has to call the API and return the results.

I don't see a technical issue with any of the last three options. You get the list of what the student can see and then compare that to your list and add the buttons for the ones that are published. 


Depending on how you handle the predefined list of pages, the last option may require that you go through the list of pages and delete or hide the non-published items.

But I've got to admit that I'm not seeing the use case for any of those four. Generally speaking, if the page isn't published then we don't want the student to see them.

View solution in original post