Java library for accessing the Canvas API

Community Member
17 5 3,027

The Java development team here at Kansas State University started our Canvas adventure off with some questionable decisions. We were originally just going to write a couple of simple LTI applications. Of course the scope and complexity of the applications grew but things were structured as a single monolithic code base. This quickly became unacceptable and we began working on splitting things into more reasonable chunks.

One of the chunks is a stand-alone API library to handle all of our interactions with the Canvas API. We wanted a central place to deal with things like pagination, masquerading and OAuth access tokens. After we started pulling this code out of our initial mess we thought the wider Canvas developer community might be able to benefit from it and decided to work towards releasing it as open source software. It is by no means a finished work but I would like to put it out there and see what others think about what we have so far.

The code is up on GitHub and available under the LGPL v3 license: kstateome/canvas-api: Java library for interacting with the Canvas LMS API

We are also publishing releases to the Sonatype Maven central repository so it can be easily used in maven based projects. The maven coordinate is edu.ksu.canvas:canvas-api

The readme file contains details on how to use the library. Following are some notes about the state and direction of development. We are also soliciting input from any other developers out there.

We do not have every API call implemented. Not even close. We are implementing them as we have time and need them for our own applications. The good news is that most of the heavy lifting of performing the HTTP requests and parsing the responses is sufficiently abstracted in common code so implementing a new call for an existing object type is usually pretty easy, especially for read operations. Creating new objects can be annoying because the Canvas documentation cannot be relied on to be accurate. You have to actually execute API calls and examine the returned data. Pushing data into the API can be tricky at times because of some API quirks that we are still discovering.

As mentioned above, we would be happy for some input from other developers. I think there are a few things we still need to change before it is really ready for more widespread adoption by others since they might be breaking changes as far as method/class signatures.

There are two specific related areas where I would love input, and they need to be set in stone quickly: Return types and exceptions. Right now every method for an API call that returns a single item has a return type of Optional<SomeCanvasObject>. As an example, if you request a course with an ID that doesn't exist, the Canvas API will return an HTTP 404 error but our library will return an empty Optional<Course>. Does it make sense to do this?

This is one of the first projects where we have used Java 8 from the ground up so we're still learning how to appropriately use some of the new features like Optional. I think this design grew out of some code where we had some shady instances of "catch(Exception e) { return null; }" going on which, of course, spawned NullPointerExceptions in other places. This got translated to Optional when we rewrote it because we wanted to avoid NPEs. It might make more sense for the methods to return the bare Course object and throw a descriptive runtime exception if there is a problem executing the request. Like throwing a custom ObjectNotFound exception if the API returns a 404 instead of returning an empty Optional. Returning null should definitely not happen. On the other hand, using Optional can be a little cleaner than having to wrap things in try/catch blocks.

That being said, you already need try/catch blocks in a lot of cases because right now every method declares throws IOException. If you pass in the wrong Canvas URL or a malformed URL, the Apache httpclient code will end up throwing an UnkownHostException or URISyntaxException or ConnectTimeoutException or something like that, all of which extend IOException. This exception will be passed all the way up to the calling code. This is kind of inconsistent with some error conditions returning an empty Optional but others letting IOExceptions to be thrown.

Another thing that might look a little odd at first glance is the requestOptions package. These are objects to encapsulate all of the (often optional) parameters you can pass to a given API call. Taking options via individual method arguments would be a bit ridiculous for some API calls that take 6+ parameters. And, if Canvas adds a new option, it would break existing code by changing the method signature. So far, so good. However you will notice that these request options classes have enums inside of them, some of which are repeated in multiple options classes. I initially tried to share the enums but ran into Canvas accepting different values on different API calls. I also found one instance of two API calls accepting the same logical options, but using different string literals to represent them. I actually opened up a GitHub issue about that one.

We still haven't ported all of our applications over to use this stand-alone library. However we have already used it to do a few things. One was to iterate through every course page in our account to do a search/replace on page content when we moved our Mediasite installation to a new URL. That process executed over 140,000 API calls over the course of a day without incident. Right now I am working on switching our Scantron LTI application over so there will probably be some missing API calls that I have to implement within the next couple of weeks for that.

We already have a pull request open on our code from someone at another institution so I'm hoping that is an indication that there is demand for a library like this and we can get some collaboration going. But first, please roast our code! :smileycool:

5 Comments
Explorer II

Thanks for sharing your code and for the write-up! I imagine Java folks will find it very useful. You've inspired me to stop procrastinating and get to work on sharing my Python library for accessing the API.

Learner II

Daniel --

We'd definitely be interested in checking out your library! We're a Python shop and we've got our own library, though it's starting to get a bit out of sync with the Canvas API, and could definitely use some work in a few areas.  Our code is on GitHub here:

GitHub - penzance/canvas_python_sdk: Canvas Python SDK 

Thanks!

--Colin

Explorer II

Hi Colin,

I've finally posted my library: Unwrapping Yet Another Python Canvas API Wrapper—and More.

Cheers,

Daniel

Community Member

Thank you Tobias and those at Kansas State for your work on the Java canvas-api. I am working on an LTI for my institution (WNMU) and found your api a great resource. As you can imagine we have different needs and so I hope to contribute some extensions to your api once I learn something about Maven. I was planning on contacting you directly when I saw something about a Hale Library fire. I hope all is well. 

Learner II

Hi All,   Sorry for resurrecting an old thread.    We are using this library and we're attempting to attach it to an ajax based application.   What we'd like is for our Ajax-based page on the client browser make a call for courses of our server, and for our server to send back the first page of results to the browser, then for the Ajax to call the next page of courses, return to browser, etc.... each page being returned to Ajax allowing for a more responsive page.   

I can see how the KState library allows for callbacks within the application, but we're not sure how to hook this up to an external calling entity like our Ajax page.   

I'm hoping someone might understand what I'm looking for and have an example of how they are using Ajax to call pages of KState data until exhausted.  

Thanks, Glen