Skip navigation
All Places > Canvas Developers > Blog > Author: Tobias Murray

Canvas Developers

2 Posts authored by: Tobias Murray

Kansas State University is proud to announce our first open source LTI application. It is an attendance taking tool. The source code is available on GitHub.

 

Previously we released a Java library to interface with the Canvas API. (blog post | code) This API library is now being used by a couple other universities and we have received several pull requests to add more functionality. Thank you to the Canvas community for embracing open source software and contributing back! We hope that this will continue.

 

Now, as part of the attendance taking application, there are a few other bits we would like to highlight. All of our LTI applications are based on an LTI launch framework to handle common launch tasks and provide common resources. We hope that others may find it useful in implementing their own LTI applications. In order to assist in learning how to use it, we have created a minimal self-contained LTI application that shows how to use the launch framework. Here are some details on these parts:

 

Attendance LTI application

This application was developed before Instructure released the Roll Call application as open source so it may not be quite as valuable now but it may still be worth a look if there is functionality you are missing in the existing Canvas experience.

 

Initially, we developed this application for the K-State Polytechnic Campus in Salina, Kanas. Their aviation maintenance program has strict guidelines from the FAA, which requires them to track contact time between students and instructors down to the minute. Later, we extended the application to be more broadly useful to the campus community.

 

Some of the features of the application include:

  • Minute versus daily attendance tracking, configurable by the instructor on a per-course basis
  • Instructors can choose to allow or prohibit students from seeing details of their attendance records
  • Attendance can be pushed to the Canvas grade book as an assignment

 

There is still some room for improvement to make this application more useful to other institutions. Depending on your existing environment, here are some specific hurdles you may face when trying to deploy this application:

  • The application was written against an Oracle database. It should not take too much effort to make the application database agnostic since we use Hibernate. We may get around to this at some point to allow for better testing.
  • We tried to avoid using K-State specific terms and branding but some did slip in. For example our SIS ID is commonly called the "Wildcat ID" and shows up as "WID" in some parts of the application.
  • The deployment process is not exactly simple. It would be great to have a docker image that packages the application and container together for easy deployment. Currently it runs on Wildfly. There is an INSTALL.md file in the repository that details every step needed to install the application in a UNIX-like environment.

 

LTI Launch Framework

This framework is based on Spring and handles LTI launch requests. (source code: GitHub) Spring Security is used to handle verifying the OAuth signature that comes with the LTI launch request. It also assists your application in getting an API access token from the user via the OAuth2 flow.

 

Because this framework is based on Spring, you must implement some interfaces and make the implementations available as Spring beans. These beans handle persisting user OAuth tokens for subsequent application launches, generally setting up the LTI application, and ensuring that the application is communicating with the correct Canvas instance. The last part is vital for hosted Canvas customers because it prevents a test version of the application from accidentally interacting with a production instance of Canvas. This mixup can readily occur when the test environment gets automatically overwritten with production settings periodically.

 

We have run into challenges as it relates to error handling in Spring. At the moment it is left mostly up to your application to handle specific errors correctly. This leads to some code duplication for handling common LTI related error conditions. As time permits, we are working to improve this problem.

 

Minimal LTI application

We created a minimal LTI application to demonstrate how to use the LTI Launch Framework. (source code: GitHub) The application outputs a simple page of text. It only authenticates the LTI launch request and then echoes back information including the username and LTI parameters being used in the application.

 

Unlike the Attendance application, this one is trivial to deploy! It uses maven to build an executable JAR which contains an embedded Tomcat server. Running it as as simple as executing the command: java -jar lti-launch-example.jar

 

Comments (and pull requests) are welcome!

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!