Export Individual Course Gradebook Via API

Jump to solution
bneporadny
Community Champion

My institution is looking at automating grades from Canvas into our SIS.  Grades in our SIS are letter grades instead of numeric. Rather than trying to translate all the grades from numeric to letter grade we were hoping to find a way to export the courses grade book so that we can setup a custom column in the grade book called final grade.  The only issue I am having is finding how to pull the grade book out of individual courses via an #api call. 

Has anyone found a way to do this?

1 Solution
James
Community Champion

 @bneporadny ,

I'm not following why you think it's necessary to involve a CSV file. Unless I'm really missing something, which is a distinct possibility, you've got a workflow in mind that takes you from point A to B to C to D to E and finally to F, when there is a direct connection between A and E so the workflow could be A to E to F. If I am missing something, I'm still not sure what you're asking for.

A CSV export will include the custom columns and you could parse it, but that information is obtainable directly from the API without messing with CSV files. The request to generate a gradebook download is an internal call, not an API one, and it starts a process that then has to wait to finish by monitoring the progress before you can download it. You could start a headless browser session, go into each course's gradebook, wait for it to load, then click the export button, wait for the export to be generated, then download it. That's a lot to automate and a lot that could go wrong.

On the other hand, there are API calls that allow you to obtain that information directly without having to mess with a CSV file and without having to wait for the CSV to generate before you can download it and without any parsing of CSV files.

I'll give you two ways I can think of to accomplish this task. One using custom gradebook columns and one using a column in the gradebook for the final grade.

Custom Column Solution

Step 1: Create a Custom Column

Use the Create a custom gradebook column endpoint to create a custom column for each course.

I sent this payload to my sandbox course:

{
  "column": {
    "title": "Final Grade",
    "position": 1,
    "hidden": false,
    "teacher_notes": false,
    "read_only": false
  }
}‍‍‍‍‍‍‍‍‍

I got this response (make a note of the column ID = 27480 for later).

{
  "id": 27480,
  "title": "Final Grade",
  "position": 1,
  "teacher_notes": false,
  "read_only": false,
  "hidden": false
}‍‍‍‍‍‍‍‍

When I go into the gradebook for that course, I see this:

298198_pastedImage_3.png

Step 2: Enter Final Grades

As a teacher, I go into the gradebook and enter grades

298202_pastedImage_2.png

298203_pastedImage_3.png

Step 3: Retrieve Grades

Now I'm going to use the List entries for a column endpoint.

Using the column ID (27480) that was generated when I created the column, I get this response (I changed the user_ids slightly)

[
  {
    "content": "A",
    "user_id": 2175000
  },
  {
    "content": "D",
    "user_id": 3346000
  }
]‍‍‍‍‍‍‍‍‍‍

Notes

You may need to use another call to match up the user_ids to a SIS ID if you haven't already saved them.

If you didn't keep track of the IDs for the custom columns when you created them, you can use the List custom gradebook columns endpoint. Then look for the one called "Final Grade".

[
  {
    "id": 27480,
    "title": "Final Grade",
    "position": 1,
    "teacher_notes": false,
    "read_only": false,
    "hidden": false
  },
  {
    "id": 2404,
    "title": "Notes",
    "position": 1,
    "teacher_notes": true,
    "read_only": false,
    "hidden": false
  }
]

Also note that I have two position 1's, so maybe I should have used position 0 when I created it. Or Maybe Canvas looks at position in ascending sort and then ID in descending sort to determine what order to put them in?

Assignment in Gradebook Solution

The other way I can think of doing this is to have a gradebook assignment that doesn't count towards the final grade. It is a letter type grading with a grading scheme attached to it. This could help enforce what teacher enter into it.  

Step 1 Create a Grading Scheme

Do this at the Account Level so that you don't have to create it for each course. If you have a standardized scale, you can put that in here and then the faculty can just type in the final percentage for the score.

I'm going to go with a 4.0 scale (A=4 ... F=0) just to make it interesting. An A is 4/4=100%, B is 3/4=75%, C is 2/4=50%, D is 1/4=25%, and F is 0/4=0%. I've set my scale to split the grade evenly on either side. Again, how you create this scheme depends on how you want faculty to enter the grades.

298209_pastedImage_17.png

Step 2 Create an Assignment for the Final Grade

I called this Final Grade Assignment (just so you could tell it apart from the Final Grade custom column I created earlier) and I did it through the GUI although it can be done through the API as well. I made it worth 4 points to match a 4.0 scale, but it can be anything. I don't want it to count towards the final grade because it is the final grade. I assigned it the grading scale I created earlier.

298206_pastedImage_12.png

I went ahead and created a rubric and used it for assigning the grade, just to make it easier for teachers to enter their grades. The problem there is that the rubric cannot be automatically created through the API.

Step 3 Enter the grades

Because I have a rubric, it's easy for the instructors to enter the grades. That extra blue arrow is from my QuizWiz: Enhancements to SpeedGrader and Quizzes‌ script that allows me to save the rubric, advance to the next student, and re-open the rubric, all with the click of a single button.

298207_pastedImage_14.png

Here's after closing the rubric:

298208_pastedImage_15.png

Step 4 Retrieve the Grades

Now it's time to get the grades from the gradebook. This requires the Submissions API. Since you're after just a single assignment, I would use the List assignment submissions endpoint.

There is a LOT more information that is returned. I've trimmed it down.

[
  {
    "id": 237117974,
    "grade": "A",
    "score": 4,
    "assignment_id": 20738248,
    "user_id": 2175000
  },
  {
    "id": 237117975,
    "grade": "D",
    "score": 1,
    "assignment_id": 20738248,
    "user_id": 3346000
  },
  {
    "id": 237117976,
    "grade": null,
    "score": null,
    "assignment_id": 20738248,
    "user_id": 8432000
  }
]‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The property that you want is the "grade" not the "score".

Note that this gives you the test student as well, it's the one with the null grade.

The list assignment submissions API has an option to include[]=user, so you can get the user details at the same time you get the grades. When you do that, you get something like this (I'm only showing one entry):

{
  "id": 237117974,
  "grade": "A",
  "score": 4,
  "assignment_id": 20738248,
  "user_id": 2175000,
  "user": {
    "id": 2175000,
    "name": "James Jones",
    "sortable_name": "Jones, James",
    "short_name": "James Jones",
    "sis_user_id": "123456",
    "login_id": "james"
  }
}

View solution in original post