Simplifies the already simple canvas api calls, and handles pagination
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
docs
tests
.gitignore
ItemClass.js
ItemsClass.js
LICENSE
README.md
api.js
canvas.js
helpers.js
main.js
package-lock.json
package.json
parse.js

README.md

Super simple to use

This module wraps the Canvas Api handling pagination and throttling. Giving easy access to the main CRUD operations, and making the other more specific calls easier as well.

// Example: Publish all Modules
const canvas = require('canvas-api-wrapper')
canvas.subdomain = 'example' // default:byui

// Gets the course shell (doesn't send any requests)
const course = canvas.getCourse(19284)

// Gets the data for all modules for this course
await course.modules.get()

// modules inherits from Array, so Array methods work
course.modules.forEach(module => {
	module.published = true
})

// Updates everything in the course that has been changed
await course.update()

Table of contents

Get Started

Install

npm i --save canvas-api-wrapper

Setup

var canvas = require('canvas-api-wrapper')
//  https://<subdomain>.instructure.com (default: byui)
canvas.subdomain = '<subdomain>' 

Authorization:

canvas.apiToken = "<TOKEN>"
# Powershell
$env:CANVAS_API_TOKEN="<TOKEN>"

# CMD
set CANVAS_API_TOKEN=<TOKEN>

# Linux & Mac
export CANVAS_API_TOKEN="<TOKEN>"

Settings

This library handles all of the throttling, so that you won't go over your rate limit. But you may want to tweek the settings to speed it up or slow it down

// the subdomain to be used in the default baseUrl
//  https://<subdomain>.instructure.com
canvas.subdomain = 'byui';

// The baseUrl to be used. Useful to overwrite when running
// a dev/local version of the canvas-lms. 
// 
//   canvas.baseUrl = https://localhost:8080
//
// The default will use the 
// subdomain setting as the subdomain, this functionality
// is not avaliable if over written
canvas.baseUrl = 'https://<subdomain>.instructure.com'

// Canvas uses a rate-limit point system to handle spamming. Canvas
// currently fills your account to 700 'points' though subject to change
// then subtracts from your 'points' every time you make a call. If 
// you go below 0 then canvas will start sending you 403 (unauthorized) 
// statuses. So when your account goes under the 'rateLimitBuffer'
// this module will halt the requests until it gets filled back to 
// the 'rateLimitBuffer'. Give it a pretty large buffer, it tends to 
// go quite a ways past the buffer before this module catches it.
canvas.rateLimitBuffer = 300;

// How many to send synchronously at the same time, the higher this
// number, the more it will go over your rateLimitBuffer
canvas.callLimit = 30;

// How much the calls are staggered (milliseconds) especially at the
// beginning so that it doesn't send the callLimit all at the same time
canvas.minSendInterval = 10;

// After it goes under the rateLimitBuffer, how often (in milliseconds) 
// to check what the buffer is at now, this should be pretty high because
// there will be a lot of threads checking at the same time.
canvas.checkStatusInterval = 2000;

Debugging

This library ambiguates which calls it's making quite a bit, especially with the wrapped calls. So to make sure it's not making excess calls. Or to just making sure it's doing what it should be you can assign canvas.oncall a function as an event handler.

canvas.oncall = function(e){
	console.log(e)
}
await canvas.getCourse(11310).pages.create({
	title:'Hello World',
	body:'<h1>Hello World</h1>',
	published: true
})
/*
{ method: 'POST',
  url: 'https://byui.instructure.com/api/v1/courses/11310/pages/',
  body:
   { wiki_page:
      { title: 'Hello World',
        body: '<h1>Hello World</h1>',
	published: true } } }
*/

Standard Calls

Use awaits or the optional callback

var modules = await canvas('/api/v1/courses/10698/modules')

/* ----------- OR -------------- */

canvas('/api/v1/courses/10698/modules', function(err,modules){
	if(err) {
		console.error(err);
		return 
	}
	console.log(modules)
})

If a post, put, or delete request the second argument is the request body

await canvas.post('/api/v1/courses/10698/modules',{
	module:{
		name:"New Module"
	}
})

If a get request, the second argument is the query object

var queriedModules = await canvas('/api/v1/courses/10698/modules',{
		search_term:'New Module'
})

Signatures

canvas(url[,query object][,callback]) // uses a GET request

canvas.get(url[,query object][,callback])

canvas.post(url[,body][,callback])

canvas.put(url[,body][,callback])

canvas.delete(url[,body][,callback])

canvas.getCourse(id)

Wrapped Calls

The CRUD operations for files, folders, assignments, discussions, modules, pages, and quizzes are wrapped for convenience. The can be accessed through the Course Class which is created through canvas.getCourse(id)

Course extends Item

var course = canvas.getCourse(17829)

// this will get the course object and attach the properties to the course
await course.get()
// allowing you to do 
course.getTitle()
course.is_public = true
await course.update()

// using getComplete, will retrieve every single item and 
// their sub items in the course. This is not recommended (of course) but 
// can be helpful in certain situations where you need every item
await course.getComplete()
course.quizzes[0].questions[0].getTitle()
course.modules[0].moduleItems[0].getTitle()
course.assignments[0].getTitle()

// Update searches through all of the children for changes, and updates
// only those with changes. So just doing course.update() will push all
// changes made anywhere in the course.
await course.update()

Items extends Array

The abstract class which all of the lists of items inherit from

  • async update( [callback] )
    • Updates all of the items that have had changes made to them or their children
const course = canvas.getCourse(19823)
await course.assignments.get()
course.assignments.forEach(assignment => {
	if(assignment.getTitle() == 'potato'){
		assignment.setTitle('Baked Potato')
		assignment.published = true
	}
})
// Only updates items named potato, because those were the only ones changed
await course.assignments.update()
  • async create( data, [callback] ) <Item>
    • Creates the item in canvas, with the given data. And adds it to the items property
    • data <Object> the properties to add to the created item
const course = canvas.getCourse(19823)
const page = await course.pages.create({
	title:'Hello World',
	body:'<h1>Hello World</h1>',
	published: true
})
console.log(page.getId())
  • async get( [callback] ) <[Item]>
    • Retrieves all of the children items from canvas
const course = canvas.getCourse(19823)
// you don't have to save it to a variable, 
// you can also just access the array through `course.modules`
// this just saves you from writing `course` everywhere
const modules = await course.modules.get()
console.log(modules)
  • async getComplete( [callback] ) <[Item]>
    • Retrieves all of the children items from canvas and all of their sub items such as the questions in a quiz or the body in a page
const course = canvas.getCourse(19823)
const modules = await course.modules.getComplete()
// normally you would have to call `get()` on each of the
// modules ( modules[0].get() ) in order to get the moduleItems
console.log(modules[0].moduleItems)
  • async getOne( id, [callback] ) <Item>
    • Retrieves a single item from canvas by id
    • id <number> the id of the item to grab
const course = canvas.getCourse(19823)
const folder = course.folders.getOne(114166)
console.log(folder)
  • async getOneComplete( id, [callback] ) <Item>
    • Retrieves a single item from canvas by id including all of it's sub items such as the questions in a quiz ( the body in page is already included because your only getting a single item )
    • id <number> the id of the item to grab
const course = canvas.getCourse(19823)
const quiz = course.quizzes.getOneComplete(114166)
console.log(quiz.questions[0])
  • async delete( id , [callback] )
    • Removes an item from canvas, and from the local list
    • id <number> the id of the item to delete
const course = canvas.getCourse(19823)
await course.quizzes.get()
const questions = await course.quizzes[0].questions.get()
await questions.delete(questions[0].getId())

Item

The abstract class for the items to inherit from

  • getId() <number>
  • getTitle() <string>
  • setTitle( title )
  • getHtml() <string>
  • setHtml( html )
  • getUrl() <string>
  • getSubs() <[Items]> - Array of children Items
  • async get( [callback] ) <Item>
    • Retrieves the item from canvas
  • async getComplete( [callback] ) <Item>
    • Retrieves the item from canvas including the sub items such as the questions in a quiz ( the body in page is already included because your only getting a single item )
  • async update( [callback] )
    • Only updates if properties have been changed on the Item since it was last gotten, also updates all of it's sub children who have been changed
  • async delete( [callback] )
    • Will delete item, and remove it from it's parent list

Assignments extends Items

Assignment extends Item

Discussions extends Items

Discussion extends Item

Files extends Items

  • Doesn't have a create method

File extends Item

Folders extends Items

Folders extends Item

Modules extends Items

Module extends Item

  • moduleItems <ModuleItems>

ModuleItems extends Items

ModuleItem extends Item

Pages extends Items

Page extends Item

Quizzes extends Items

Quiz extends Item

  • questions <QuizQuestions>

QuizQuestions extends Items

QuizQuestion extends Item

Item Gets and Sets

Type getId getTitle/setTitle getHtml/setHtml getUrl getSubs
Course id name /courses/<course> [ files<Files>, folders<Folders>, assignments<Assignments>, discussions<Discussions>, modules<Modules>, pages<Pages>, quizzes<Quizzes> ]
Assignment id name description html_url
Discussion id title message html_url
File id display_name /files/?preview=<id>
Folder id name folders_url
Module id name /modules#context_module_<id> [ moduleItems<ModuleItems> ]
ModuleItem id title html_url
Page page_id title body html_url
Quizzes id title description html_url [ questions<QuizQuestions> ]
QuizQuestion id question_name question_text /quizzes/<quiz>/edit#question_<id>