I've written a basic API script in PHP using cURL - and successfully used a version of it on another API, this one is specifically to handle domain DNS management on DigitalOcean - and I can't send data?
I understand there is a PHP library available, I'm not after something that full featured or bloated with dependencies - just something small to use locally and primarily to help me understand how RESTful API's work a little better in practice - an educational exercise
function basic_api_handle($key, $method, $URI, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer '.$key,
'Content-Type: application/json')
);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_URL, $URI);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
var_dump(basic_api_handle($api_key, 'POST', 'https://api.digitalocean.com/v2/domains', array('name' => 'my-domain.tld', 'ip_address' => '1.2.3.4')));
This works with a GET request, such as listing the domains on the account but seems to fail at posting/sending data... this results in "unprocessable_entity" and "Name can't be blank" - as the name is not blank and is correctly formatted (as far as I can tell) it suggests to me the data is not being sent correctly?
I've tried json encoding the data (seen in code), not json encoding, url encoding with and without json encoding and various other options with no luck.
I've seen a few posts online about this exact same issue specifically with DigitalOcean's API (and a another) but no one had an explanation (other than give up and use the library or something to that affect).
Using cURL directly from a terminal does work etc so there is nothing wrong with the API for creating a domain.
As far as I understand, the authentication is working, and the general setup works as I can list domains within the account, I just cant POST or PUT new data. I've been though the API's documentation and can't see what I'm doing wrong, maybe some sort of wrong encoding?
Any help would be much appreciated! :)
Edit: After much work and research even other simple API handlers do not work with Digital Ocean (such as https://github.com/ledfusion/php-rest-curl) - is there something this API in particular needs or am I missing something fundamental about API's in general?
Add the Content-Length header and use CURLOPT_POST option for POST requests
function basic_api_handle($key, $method, $URI, $data) {
$json = json_encode($data)
$headers = array(
'Authorization: Bearer '.$key,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $URI);
if ( $method === 'POST' ) {
curl_setopt($curl, CURLOPT_POST, 1);
} else {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
array_push($headers, 'Content-Length: ' . strlen($json) );
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers)
curl_setopt($ch, CURLOPT_POSTFIELDS, $json );
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
Maybe this will work for you:
function basic_api_handle($key, $method, $URI, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); // <-- Should be set to "GET" or "POST"
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // <-- Maybe the SSL is the problem
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"); // <-- I am not familiar with this API, but maybe it needs a user agent?
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer '.$key,
'Content-Type: application/json')
);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_URL, $URI);
curl_setopt($ch, CURLOPT_POST, count($data)); // <-- Add this line which counts the inputs you send
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
It can also be a problem of a header you should sent and your missing it.
It could be a 307 or 308 http redirect.
Maybe "https://api.digitalocean.com/v2/domains" redirects to another url.
If this is the case, try adding:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
to make curl follow the redirection and keep the parameters. It is suggested that you also use:
curl_setopt($curl, CURLOPT_POSTREDIR, 3);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
to keep the request body. Hope it helps.