422 Error when making POST Request to Favorite Courses API

Jump to solution
lbeveridge
Community Explorer

Hello,

I am working some custom Javascript that needs to be able to add and remove favorite courses for users through the Canvas API. I can get the list of a user's favorites without any issues, but I am getting a 422 "unprocessable entity" response when I try to do a POST request to add a favorite course for a user.

First, I tried making the POST request without any authorization, since the GET request for favorite courses does not require it, however I got the 422 response. Then, I used Chrome's dev tools to look into the request that Canvas sends when a user clicks on the start icon in the "All Courses" menu to favorite a course. I found that the payload Canvas sends includes an "authenticity_token" which is called the "_csrf_token" in Canvas's cookies. This token is regenerated each time it is used, but I tried manually adding it to my code to see if that would solve the error. Here is the code I am currently using:

 

data = {}
fetch('<our canvas url>/api/v1/users/self/favorites/courses/<course number>', {
  method: 'POST',
  headers: {'Content-Length': 0, authenticity_token: '<csrf_token copied from Canvas's cookies>'},
  body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
  console.log('Success:', data);
})
.catch((error) => {
  console.error('Error:', error);
});

 

With this code, I still unfortunately get the 422 response. The user I am testing this with is enrolled in the course that I am trying to favorite, and the course is not already favorited. I am thinking I must be doing something wrong with this request!

I would greatly appreciate assistance with this if anyone has ideas as to why this error is occurring!

Labels (5)
0 Likes
1 Solution
robotcars
Community Champion

@lbeveridge 

I've never tried to pass the token in the form data, just the headers. I did some practice with this awhile back for XHR testing and applied it to your fetch. I was able to make this work. Since the token is refreshed, I use a function to strip the token from the cookie and decode it, the function making it reusable for subsequent requests. You can see this by making any AJAX request on the page and calling CSRFtoken().

 

const CSRFtoken = function() {
  return decodeURIComponent((document.cookie.match('(^|;) *_csrf_token=([^;]*)') || '')[2])
}

fetch('/api/v1/users/self/favorites/courses/1234567', {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'accept': 'application/json',
      'X-CSRF-Token': CSRFtoken()
    },
    //body: JSON.stringify(data),
  })
  .then(response => response.json())
  .then(data => {
    console.log('Success:', data);
  })
  .catch((error) => {
    console.error('Error:', error);
  });

 

 

 

 

View solution in original post