Found this content helpful? Log in or sign up to leave a like!

Canvas Rubrics API Criteria

Jump to solution
eldridgm
Community Explorer

Hello,

I am looking to make a bulk update to the titles of rubrics in courses on our instance of Canvas and I am running into an issue. After some testing I am encountering the issue of the criteria being removed once the title update is pushed. I am using Excel and VBA to complete this task to try and make it user friendly for those who might use it in the future in the office so I am opting to use a json format when I make the PUT call. I will also say I am a bit of a novice when it comes to this so I may get some terminology incorrect.

I cannot find the exact format that is necessary nor can I find what fields are required in order to make sure that all of the data is saved. I noticed that the field that contains the criteria is titled "data" in the GET return which is also slightly confusing since we have to PUT a criteria object. I tried initially to take the return, change the title and change "data" to "criteria" which gave me a 500 error. I also tried using a format where you number the objects (ex: "criteria":{"0":{"id":) which also did not yield any results.

If anyone has any details or tips for how to do this I would be very appreciative as this is the only call I have experienced so far that has this behavior and I am at a loss for how to do this. 

Labels (1)
0 Likes
1 Solution
James
Community Champion

@eldridgm 


If I understand correctly, you're trying to just change the title of the entire rubric, not the titles on the individual criteria. Unfortunately, the PUT method is used to completely replace an existing resource. That is not the way that Canvas typically uses it, but in this case, you cannot change just the title.

You need to use the Rubrics API to accomplish this.

If I have a course 896851 with a rubric 1027044 that has a title of "Teacher Observation Rubric", I might be tempted to try this:

PUT /api/v1/courses/896851/rubrics/1027044

My payload would be

{
  "rubric": {
    "title": "Revised Teacher Observation Rubric"
  }
}

This does, indeed, change the title, but it wipes out all of the criterion for the rubric. You are playing around in your beta instance or somewhere it doesn't matter if you ruin something, right?

When you look at the documentation for updating a single rubric,  you see that most if it is under rubric, including the criteria. When you get the rubric object, the criteria is under data.

I'm changing the rubric as I had 20 criteria in that one and that's a bit excessive for an example. I'm going to switch to rubric 1413806, which only has two criteria.

I start by getting the existing rubric with GET /api/v1/courses/896851/rubrics/1413806

{
  "id": 1413806,
  "title": "Discussion Rubric (1)",
  "context_id": 896851,
  "context_type": "Course",
  "points_possible": 10.5,
  "reusable": false,
  "public": false,
  "read_only": false,
  "free_form_criterion_comments": false,
  "hide_score_total": false,
  "data": [
    {
      "id": "_4882",
      "description": "Initial Post",
      "long_description": null,
      "points": 5.25,
      "mastery_points": null,
      "ignore_for_scoring": null,
      "learning_outcome_migration_id": null,
      "title": "Initial Post",
      "criterion_use_range": null,
      "ratings": [
        {
          "description": "Awesome",
          "long_description": null,
          "id": "_9056",
          "criterion_id": "_4882",
          "points": 5.25
        },
        {
          "description": "Good",
          "long_description": null,
          "id": "_8146",
          "criterion_id": "_4882",
          "points": 4.5
        },
        {
          "description": "Okay",
          "long_description": null,
          "id": "_5013",
          "criterion_id": "_4882",
          "points": 3.75
        },
        {
          "description": "Fair",
          "long_description": null,
          "id": "_3805",
          "criterion_id": "_4882",
          "points": 3
        },
        {
          "description": "Poor",
          "long_description": null,
          "id": "_1269",
          "criterion_id": "_4882",
          "points": 2.25
        },
        {
          "description": "None",
          "long_description": null,
          "id": "_6210",
          "criterion_id": "_4882",
          "points": 0
        }
      ]
    },
    {
      "id": "_7722",
      "description": "Follow-Up",
      "long_description": null,
      "points": 5.25,
      "mastery_points": null,
      "ignore_for_scoring": null,
      "learning_outcome_migration_id": null,
      "title": "Follow-Up",
      "criterion_use_range": null,
      "ratings": [
        {
          "description": "Awesome",
          "long_description": null,
          "id": "_590",
          "criterion_id": "_7722",
          "points": 5.25
        },
        {
          "description": "Good",
          "long_description": null,
          "id": "_4751",
          "criterion_id": "_7722",
          "points": 4.5
        },
        {
          "description": "Okay",
          "long_description": null,
          "id": "_2116",
          "criterion_id": "_7722",
          "points": 3.75
        },
        {
          "description": "Fair",
          "long_description": null,
          "id": "_179",
          "criterion_id": "_7722",
          "points": 3
        },
        {
          "description": "Poor",
          "long_description": null,
          "id": "_3988",
          "criterion_id": "_7722",
          "points": 2.25
        },
        {
          "description": "None",
          "long_description": null,
          "id": "_4577",
          "criterion_id": "_7722",
          "points": 0
        }
      ]
    }
  ],
  "rating_order": "descending",
  "button_display": "numeric"
}

Not only do you need to move things around, but some of the information isn't allowed to send back when you're updating the rubric. You also need to remove the arrays and replace them with hashes where the keys are integers. I use the index of the element in the array.

That is, instead of [ "John", "Tom" ], you write { "0": "John", "1": "Tom" }

I was able to use a PUT statement to update my rubric, changing the title and keeping the criteria.

PUT /api/v1/courses/896851/rubrics/1413806

{
  "rubric": {
    "title": "Improved Discussion Rubric",
    "points_possible": 10.5,
    "free_form_criterion_comments": false,
    "criteria": {
      "0": {
        "id": "_4882",
        "description": "Initial Post",
        "long_description": null,
        "points": 5.25,
        "criterion_use_range": false,
        "ratings": {
          "0": {
            "description": "Awesome",
            "long_description": null,
            "id": "_9056",
            "points": 5.25
          },
          "1": {
            "description": "Good",
            "long_description": null,
            "id": "_8146",
            "points": 4.5
          },
          "2": {
            "description": "Okay",
            "long_description": null,
            "id": "_5013",
            "points": 3.75
          },
          "3": {
            "description": "Fair",
            "long_description": null,
            "id": "_3805",
            "points": 3
          },
          "4": {
            "description": "Poor",
            "long_description": null,
            "id": "_1269",
            "points": 2.25
          },
          "5": {
            "description": "None",
            "long_description": null,
            "id": "_6210",
            "points": 0
          }
        }
      },
      "1": {
        "id": "_7722",
        "description": "Follow-Up",
        "long_description": null,
        "points": 5.25,
        "criterion_use_range": false,
        "ratings": {
          "0": {
            "description": "Awesome",
            "long_description": null,
            "id": "_590",
            "points": 5.25
          },
          "1": {
            "description": "Good",
            "long_description": null,
            "id": "_4751",
            "points": 4.5
          },
          "2": {
            "description": "Okay",
            "long_description": null,
            "id": "_2116",
            "points": 3.75
          },
          "3": {
            "description": "Fair",
            "long_description": null,
            "id": "_179",
            "points": 3
          },
          "4": {
            "description": "Poor",
            "long_description": null,
            "id": "_3988",
            "points": 2.25
          },
          "5": {
            "description": "None",
            "long_description": null,
            "id": "_4577",
            "points": 0
          }
        }
      }
    }
  },
  "rubric_association": {
    "use_for_grading": false,
    "hide_score_total": false,
    "hide_points": false,
    "hide_outcome_results": false
  }
}

 

As an unsolicited comment, I would not use Excel and VBA to do this. It's not going to be easy for anyone to step in and maintain and there are other programming languages that will be easier to look at and understand what you're doing. A lot of non-professional programmers like Python. I'm not a professional and use JavaScript. If you want someone to understand what you're doing (you say you're using JSON), you also want to pick a more popular language. JSON is the more modern choice, but it wasn't intended to be human readable; it was designed so that computers can understand it. I would recommend using JSON, but VBA requires extra steps to use JSON. Also, VBA usage is fairly rare. According to the Stack Overflow 2025 Developer Survey, only about 3.3% of developers use VBA. Compare that to JavaScript (68.8%) and Python (54.8%). For those learning to code, Python is used by 71.8% of developers and JavaScript by 62.8%; VBA is at 3.4%. If you want to make it easy for someone to take it over in case you're not available, Excel and VBA probably aren't the best choices.

View solution in original post