cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
kreut
Community Participant

Can't make a PHP POST request to the Canvas API

Jump to solution

Hi,

I'm trying to make my first API calls using my Canvas token.  I'm able to to do GET requests via PHP but I'm having problems doing POST requests.  Below is a copy of my unsuccessful POST request via PHP (no errors but after listing the external tools, I can see that I'm not actually creating one and I'm not getting any sort of json back) and my successful POST with cURL via the terminal.  I've changed the url and secret key information.  

Might anyone be able to spot the issue?

url = 'https://some_url.com/api/v1/courses/1463675/external_tools';

$data = [
'name' => 'First tool',
'privacy_level' => 'name_only',
'consumer_key' => 'mykey',
'shared_secret' => 'mysecret',
'url'=>'https://example.com/ims/lti'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$authorization = "Authorization: Bearer " . CANVAS_TOKEN;
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json', $authorization]);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);


$result = curl_exec($ch); // Execute the cURL statement

curl_close($ch); // Close the cURL connection
var_dump($result);

curl -X POST 'https://some_url.com/api/v1/courses/1463675/external_tools' \
-H "Authorization: Bearer my_super_secret_key" \
-F 'name=First Tool' \
-F 'consumer_key=asdfg' \
-F 'shared_secret=lkjh' \
-F 'url=https://example.com/ims/lti' \
-F 'privacy_level=name_only' \
-F 'custom_fields[key1]=value1' \
-F 'custom_fields[key2]=value2' \
-F 'course_navigation[text]=Course Materials' \
-F 'course_navigation[enabled]=true'
Labels (1)
Tags (3)
1 Solution

Accepted Solutions
James
Community Champion

 @kreut  

The first thing I notice is that you are sending mixed signals to the server. You're telling it to use JSON, but then you're sending it a url-encoded payload.

If you use content-type:application/json, then you need to json_encode() your object before adding it to CURLOPT_POSTFIELDS.

If you do not specify the content-type, then you should just put your object into CURLOPT_POSTFIELDS without encoding it and it will convert it for you.

You shouldn't (it may work, but not recommended) use http_build_query() with a POST, that's for GET (since there is no content-type) and some PUT (so you can avoid content-type).

View solution in original post

4 Replies
James
Community Champion

 @kreut  

The first thing I notice is that you are sending mixed signals to the server. You're telling it to use JSON, but then you're sending it a url-encoded payload.

If you use content-type:application/json, then you need to json_encode() your object before adding it to CURLOPT_POSTFIELDS.

If you do not specify the content-type, then you should just put your object into CURLOPT_POSTFIELDS without encoding it and it will convert it for you.

You shouldn't (it may work, but not recommended) use http_build_query() with a POST, that's for GET (since there is no content-type) and some PUT (so you can avoid content-type).

View solution in original post

kreut
Community Participant

Thank you! It worked once I took both of your suggestions...

And I should have realized that it was performing some sort of GET since it looked like it was trying to load up the url instead of POST to it.

Cheers,

Eric

James
Community Champion

I didn't know I had two suggestions there, I thought I just wrote the same thing in a couple of different ways. But I'm glad you got it working.

Although it wasn't the reason the script wasn't working, I would also add an accept:application/json header.

Some API calls return a while(1); in front of the JSON if you don't. This is definitely the case with a GET in a browser and I think I've seen it on occasion outside of the browser. Most of the time it works without it, but then you forget about it until it bites you. I always include the accept header when I make API calls.

kreut
Community Participant

Thank you for the additional info...