cancel
Showing results for 
Search instead for 
Did you mean: 
p_a_robinson
Community Participant

Have you succeeded in using the API to create assignments?

Jump to solution

I've been using the canvas API for a variety of things, and generally it works very well.  For the life of me, though, I cannot seem to create a new assignment using it.  Has anyone else managed to do this?  All I ever get in response is "400 Bad request", which doesn't make debugging easy!  I'm sending JSON data via a POST request and setting the Content-Type header of the request to 'application/json', but nothing works.  I can retrieve existing assignments fine.

Does anybody know if the API is broken?  Has anyone succeeded in creating an assignment programmatically using the API?

Tags (3)
1 Solution

Accepted Solutions
p_a_robinson
Community Participant

Thanks for the reply, James.  I had not explicitly set the content-length, because I'm writing code in C# and using the System.Net.WebClient class, which automatically sets it from the content.  It is definitly being set; I've checked the raw HTML which is being sent to canvas using Fiddler. 

I have now found the answer.  Although it is not clear (at least to me) in the documentation, the JSON sent as the body of the POST request needs to have a top-level element called 'assignment'.  For example, this is valid, and works:

{

  "assignment": {

    "name": "Test assessment 1",

    "submission_types": [

      "none"

    ],

    "points_possible": 1,

    "grading_type": "points",

    "due_at": "2015-10-18T00:00:00+01:00",

    "muted": "true",

    "published": "false"

  }

}

whereas this (which Is what the documentation seems to suggest) won't work:

{

    "name": "Test assessment 1",

    "submission_types": [

      "none"

    ],

    "points_possible": 1,

    "grading_type": "points",

    "due_at": "2015-10-18T00:00:00+01:00",

    "muted": "true",

    "published": "false"

}

Like many things, it's obvious once you spot it.  Thanks to everyone for their suggestions.

View solution in original post

10 Replies
MattHanes
Community Champion

I have succeeded doing this by passing the assignment criteria as parameters but not formatted as JSON. I just tried it as JSON and I kept getting that same error. I don't know if it helps, but here is an example of passing the information as a parameter in the URL POST:

http://[your_institution].instructure.com/courses/123456/assignments?assignment[name]=AssignmentName...

p_a_robinson
Community Participant

Thanks for takin gthe time to check.  I'm glad I'm not the only one who experiences the problem.  It works for me with URL POST, too.  It just seems like a very awkward way to have to do it, especially as creating a decent assignment requires quite a lot of parameters.  I think I might report this as a bug.

No problem. I had the same type of issue with the Quiz Extensions API and reported it as a bug. They got back to me weeks later and it turns out the documentation was just a little off. So maybe that's the case here too!

The live API seems to work though. It still doesn't work for the Quiz Extensions API.

p_a_robinson
Community Participant

Yes, I checked the live API (I only found out about that today - what a boon!), but Fiddler shows that it uses URL encoding, not JSON.  I'm not convinced that the JSON POSTing is actually implemented.  I might try it with one or two of the other functions.

James
Community Champion

 @p_a_robinson ,

I use the create assignment API with JSON.

When using POST (or PUT) with JSON, you need to add two headers. You only mention one in your comment, so I'm not sure if that was oversight in the mention or oversight in the implementation.

I JSON encode my parameters to a string and then find the length of that string.

Then I add these two HTTP headers

     Content-Type: application/json

     Content-Length: length of string

Then, because I'm using CURL within PHP, I set the CURLOPT_POSTFIELDS to the data string.

I don't remember where I saw the Content-Length, but I'm pretty sure I wouldn't have put it in there if I hadn't found that solution somewhere.

I don't have any assignments to create right now, so I created a dummy course and re-ran the script I used in the Spring, just to confirm it was still working The assignments were created correctly.

Try the content-length thing. If that doesn't work, perhaps you could share an example object you're trying to post. There might be something there that isn't properly set. There are certain fields that are required depending on the type of assignment that it is. Like you said, it's hard for you to diagnose a 400 bad request error, but it's even harder for those of us who don't know what you're trying to send.

That doesn't explain  @MattHanes ​' success in one case and error with JSON, but it may help us find something we're missing.

p_a_robinson
Community Participant

Thanks for the reply, James.  I had not explicitly set the content-length, because I'm writing code in C# and using the System.Net.WebClient class, which automatically sets it from the content.  It is definitly being set; I've checked the raw HTML which is being sent to canvas using Fiddler. 

I have now found the answer.  Although it is not clear (at least to me) in the documentation, the JSON sent as the body of the POST request needs to have a top-level element called 'assignment'.  For example, this is valid, and works:

{

  "assignment": {

    "name": "Test assessment 1",

    "submission_types": [

      "none"

    ],

    "points_possible": 1,

    "grading_type": "points",

    "due_at": "2015-10-18T00:00:00+01:00",

    "muted": "true",

    "published": "false"

  }

}

whereas this (which Is what the documentation seems to suggest) won't work:

{

    "name": "Test assessment 1",

    "submission_types": [

      "none"

    ],

    "points_possible": 1,

    "grading_type": "points",

    "due_at": "2015-10-18T00:00:00+01:00",

    "muted": "true",

    "published": "false"

}

Like many things, it's obvious once you spot it.  Thanks to everyone for their suggestions.

View solution in original post

James
Community Champion

Yes, that's correct. Like you said, after you realize what is happening, it make sense. Now you will know what to do when you get to other places like creating pages or quizzes, which also require a top-level object.

What the "documentation seems to suggest" is showing you what an assignment object looks like. When you retrieve assignments, you will get an object (or an array of objects) that look like that. When you create (or often when you update), you need to show it's an object rather than just a bunch of unrelated items and making them belong to an assignment, question, answer, or wiki_page object is how that's done. But be sure to follow the instructions on creating because what you send back is sometimes not what you get. In particular, the Quiz Questions API returns an answer object, but the answer object you use when you create a question has different field names than the object that is returned when you retrieve one.

As for JSON vs form fields, I've switched to using JSON for POSTs and PUTs.in any new code I write as found it easier, safer, and less verbose to work with. Without JSON, for a PUT you have to encode the payload into the query string, which might be length limited​ and may get logged into the server logs. When I was making changes to the content pages, it was prudent to make sure I didn't accidentally truncate the content of a page and I also didn't want the content showing up in the log files, so I switched to JSON. I've just stuck there since. As long as I'm not uploading files, it works. I wish I could use it on GETs, but that's not supported.

I was not using a REST Client and directly manipulating the CURL, so maybe that's why I had to use the Content-Length.

Anyway, I'm glad you got it figured out.

I'm glad you figured it out! I really thought I tried that and it didn't work. Looking at my notes, after "assignment" I forgot to put a colon! I'm such a noob!

James
Community Champion

 @MattHanes ​,

Not that it's worth much, but I personally think you have it backwards. Instead of being a noob, you're a boon to the process. You're one of the few others providing code for the masses and I admire the work you do.

That said, I'll give you the noob thing because when you hold yourself up as an expert, other people start to expect it.