Your Community is getting an upgrade!
Read about our partnership with Higher Logic and how we will build the next generation of the Instructure Community.
Found this content helpful? Log in or sign up to leave a like!
I'm working on an LTI app, and am needing to send grades to Canvas in bulk. I'm using the endpoint:
This creates an async job and returns a progress object as expected. The job fails, however, because the submitted user id is null. There, however, does not seem to be a user id parameter for this end point, so I am not sure what to do to debug or how to make sure it is sent. Is this possibly a problem in the authorization process?
For reference, here is the progress query result:
while(1);{"id":2926799,"context_id":1876255,"context_type":"Course","user_id":null,"tag":"submissions_update","completion":null,"workflow_state":"failed","created_at":"2016-06-27T18:33:39Z","updated_at":"2016-06-27T18:33:40Z","message":"Couldn't find User(s) with API ids ''","url":~CANVAS URL~}
Solved! Go to Solution.
Ok, my request was formulated correctly, and do know to check the progress url for the failed status, i just wasn't putting that down because I thought that the source of the error was showing up in the initial queued progress. That last bit on the failure scenario ended up sending me on the right path. I blame this one on a mix of stupidity and a misleading error message.
It turns out I was sending a null student ID. What threw me off was the message returned from the failed progress object: "message" : "Couldn't find User(s) with API ids ''", listed right below a field showing "user_id" : null. This led me to think that the user_id in the progress object being null was the problem, when the user id that was problematically null was the student ID I was submitting. So, problem solved.
It is difficult to know why you are having issues without seeing how you are forming your API call.
Can you post a curl example, showing all parameters that you are sending?
It's embedded deep in php, and I couldn't find a good way to get all of the information I needed from curl_info.
Here's all of the relevant contents of the request sent to my local install of Canvas, pulled from Wireshark. user_id in the response is still left as null.
Hypertext Transfer Protocol
POST /api/v1/courses/1/assignments/50/submissions/update_grades HTTP/1.1\r\n
[Expert Info (Chat/Sequence): POST /api/v1/courses/1/assignments/50/submissions/update_grades HTTP/1.1\r\n]
[POST /api/v1/courses/1/assignments/50/submissions/update_grades HTTP/1.1\r\n]
[Severity level: Chat]
[Group: Sequence]
Request Method: POST
Request URI: /api/v1/courses/1/assignments/50/submissions/update_grades
Request Version: HTTP/1.1
Host: localhost:3000\r\n
User-Agent: GuzzleHttp/6.2.0 curl/7.43.0 PHP/5.5.27\r\n
Authorization: Bearer e1rXcjVWLvu7w8pTebuj3spdpX22kyBNQAru0a1xyAc7RtJxEgEMSfk3Qr7RxmPr\r\n
Content-Type: application/json;charset=UTF-8\r\n
Content-Length: 46\r\n
\r\n
[Full request URI: http://localhost:3000/api/v1/courses/1/assignments/50/submissions/update_grades]
[HTTP request 1/1]
[Response in frame: 312]
Body:
JavaScript Object Notation: application/json
Object
Member Key: "grade_data"
Object
Member Key: "4"
Object
Member Key: "posted_grade"
String value: 0.2500
@kmoverall This doesn't help me too much, it looks cut off. That is not a complete json object definition.
I strongly suggest you use cURL to test your API call, and verify that you understand the parameters.
If you can generate a successful result using cURL, then you can focus on how you are passing the parameters to the API call in your code.
Look at the API documentation for an example of what the cURL command would look like:
Submissions - Canvas LMS REST API Documentation
One thought I have, are you sure you are passing the correct <student_id>?
If you are not passing the correct <student_id>, I could see that generating the error you are receiving.
I'm not clear on how that isn't a complete JSON object definition. It's not the standard format, since it was outputted by Wireshark. It does have all of the data required for the request though, and the server has no trouble parsing it. I am quite positive it is the entire object as well.
Double checked the student ID, it is correct.
I attempted it with cUrl, and here the request:
curl 'http://localhost:3000/api/v1/courses/1/assignments/50/submissions/update_grades' \
-X POST \
-H "Authorization: Bearer Qe6mSzqkV2VLVjUd8FPOPdoYWKh0khb7dErBQa6BuB77nGF7K9if3sEU8w5iI3jE" \
-H "Content-Type: application/json" \
-d '{"grade_data" : { "4" : { "posted_grade" : "0.25%" } } }'
And the response:
{"id":69,"context_id":1,"context_type":"Course","user_id":null,"tag":"submissions_update","completion":null,"workflow_state":"queued","created_at":"2016-06-29T21:28:21Z","updated_at":"2016-06-29T21:28:21Z","message":null,"url":"http://localhost:3000/api/v1/progress/69"}
The response is the same if grade_data is sent with the -F argument, as though it were a form, as shown in the example request.
As you can see, the user_id is still null. The Progress documentation states that this is "the id of the user who started the job". When checking the /users/self endpoint, the user with id=1 does show up, so Canvas does seem aware of who is accessing it from other endpoints.
Looking at the syntax of your curl command, I think you have a couple of typos.
I just tested this call against my test environment, and it is working properly.
Here is my command that worked:
curl https://mysite.test.instructure.com/api/v1/courses/1234/assignments/5678/submissions/update_grades
-X POST
-F "grade_data[110][posted_grade]=88"
-F "grade_data[109][posted_grade]=95"
-H "Authorization: Bearer myprivatesecuritytoken"
After running this command, I looked at the gradebook in Canvas and confirmed that the two grades had been updated.
Next I inspected the result received from the call, here it is:
{
"id" : 6974,
"context_id" : 1040,
"context_type" : "Course",
"user_id" : null,
"tag" : "submi
ssions_update",
"completion" : null,
"workflow_state" : "queued",
"created_at" : "2016-06
-30T12:50:59Z",
"updated_at" : "2016-06-30T12:50:59Z",
"message" : null,
"url" : "https://mysite.test.instructure.com/api/v1/progress/6974"
}
Important Note: this result is simply telling you that your request was successfully received. "workflow_state" suggests that this is running as a workflow, similar to a SIS import, and that is is not returning a synchronous result. If you don't understand what this means, post another question and I'll explain.
You should also make note of the "url" that was sent back, which is an API call. The "progress" value of the url strongly suggests that this API call will give you the status of the workflow.
It sounds as though you are looking at "user_id": null and deciding the request has failed.
However, you make the API call given in the results to to get the actual status (see "url" value in results above in bold). Here is the curl command to get the results, the API url is found in the results of the previous API call, shown in bold above:
curl https://mysite.test.instructure.com/api/v1/progress/6974
-H "Authorization: Bearer myprivatesecuritytoken"
Here is the result I received:
{
"id": 6974,
"context_id": 1040,
"context_type": "Course",
"user_id": null,
"tag": "submissions_update",
"completion": 100.0,
"workflow_state": "completed",
"created_at": "2016-06-30T12:50:59Z",
"updated_at": "2016-06-30T12:51:01Z",
"message": null,
"url": "https://mysite.test.instructure.com/api/v1/progress/6974"
}
You will make this call as many times as needed until "completion" give you back 100.0, or a failure code.
See the definition of the Progress API for details on expected values: Progress - Canvas LMS REST API Documentation
Notice in this result completion is 100%.
So the next step is to understand what to expect if the API call to update the grades fails.
Using the first curl command above, I passed invalid student_id values.
The result I got back was essentially the same result, telling me that the workflow_state was queued.
This demonstrates why you have to make the second API call to get the status of the job.
I was not able to determine that the workflow had failed until I made the second API call.
Here is the result I get from the second API call when the job fails:
{
"id" : 6975,
"context_id" : 1040,
"context_type" : "Course",
"user_id" : null,
"tag" : "submissions_update",
"completion" : null,
"workflow_state" : "failed",
"created_at" : "2016-06 -30T12:59:44Z",
"updated_at" : "2016-06-30T12:59:45Z",
"message" : "Couldn't find User(s) with API ids '0'",
"url" : "https://mysite.test.instructure.com/api/v1/progress/6975"
}
Notice this result clearly tells me that the API request has failed.
Follow these steps:
I hope this helps.
Ok, my request was formulated correctly, and do know to check the progress url for the failed status, i just wasn't putting that down because I thought that the source of the error was showing up in the initial queued progress. That last bit on the failure scenario ended up sending me on the right path. I blame this one on a mix of stupidity and a misleading error message.
It turns out I was sending a null student ID. What threw me off was the message returned from the failed progress object: "message" : "Couldn't find User(s) with API ids ''", listed right below a field showing "user_id" : null. This led me to think that the user_id in the progress object being null was the problem, when the user id that was problematically null was the student ID I was submitting. So, problem solved.
To interact with Panda Bot, our automated chatbot, you need to sign up or log in:
Sign InTo interact with Panda Bot, our automated chatbot, you need to sign up or log in:
Sign In