tags:

views:

48

answers:

5

I'm trying to do a simple post to a web service using CURL and their API but I'm getting a 422 response. My code looks like:

include 'CurlRequest.php';

$secret_key = 'mykeyhere';
$group_id = 'group_id';

$postData = array(
    'group_id' => $group_id,
    'key' => $secret_key,
    'status' => 'test'
);

$curl = new CurlRequest('http://coopapp.com/statuses/update.json');
$curl->exec(array(
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($postData)
));

I'm using an existing Curl Library to handle the posts. I'm sure it has something to do with the way I'm formatting the POST url (I've tried a bunch of different ways) or the way I'm posting the data.

Their docs are here: http://coopapp.com/api/statuses

Thanks!

A: 

I don't think you should json_decode() the POSTFIELDS data, should you? The response will be JSON, but the input is expected as POST fields. According to the manual:

The full data to post in a HTTP "POST" operation. To post a file, prepend a filename with @ and use the full path. This can either be passed as a urlencoded string like 'para1=val1&para2=val2&...' or as an array with the field name as key and field data as value. If value is an array, the Content-Type header will be set to multipart/form-data.

this should work:

$curl = new CurlRequest('http://coopapp.com/statuses/update.json');
$curl->exec(array(
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => $postData
));
Pekka
+1  A: 

The HTTP error seems odd for an API like this.

The Co-Op API doc is a bit... well.. confusing on the status update, as it talks about POSTing the data, but the example shows a query string. What you could do, is try putting the stuff in the query string, or not using CURL. PHP's file_get_contents is actually a usable HTTP client, if you pass it enough parameters. So try this:

$params = array(
    'group_id' => $group_id,
    'secret_key' => $secret_key,
    'status' => 'test'
);
$context = stream_context_create(
   array(
    'http' => array(
     'method' => 'POST'
   ))
);
file_get_contents("http://coopapp.com/statuses/update.json?" .
   http_build_query($params), false, $context);

And if that doesn't work, rule out CURL errors, by doing the same thing without CURL:

$params = array(
    'group_id' => $group_id,
    'secret_key' => $secret_key,
    'status' => 'test'
);
$context = stream_context_create(
   array('http' => array(
     'method' => 'POST',
     'content' => http_build_query($params)      
   ))
);
file_get_contents("http://coopapp.com/statuses/update.json", false, $context);

Note that I haven't tested the code, so some error-checking/fixes might be needed.

TuomasR
Good points. The HTTP error is really odd - 422 seems to be usually reserved for WebDAV, and I bet the official description of the status code `The request was well-formed but was unable to be followed due to semantic errors.` doesn't match what the API intended to say.
Pekka
There should be nothing confusing about posting a query string. That's the way form data is often sent from a browser, and many apis accept post data that way.
GZipp
@GZipp: Yes, I know, but why use POST if there's no post body? If you use POST, a lot of programmers will try to pass the variables as post body, as that's how most of the time parameters are passed in post. Hence -> room for error in understanding.
TuomasR
No argument there, and I admit that I myself was confused by the documentation and your code. Your second example doesn't, as you say, do "the same thing" as the first; it will send the query string in the request body, even though the documentation seemingly indicates that it should be in the uri a la GET. (If your first example doesn't work for op, then it would seem to me the api is broken or the documentation is in error.)
GZipp
Ah, oops. My bad.
TuomasR
Very nice demo of the flexibility of file_get_contents(), btw, although the 'http' context parameter needs to be wrapped in an array. :)
GZipp
Ah, my bad #2 ;)
TuomasR
+1  A: 

Here's a quote from the api page

POST /statuses/update.xml?group_id=#{group_id}&status=An%20encoded%20status&key=#{secret_key}

its supposed to be key not secret_key

$postData = array(
    'group_id' => $group_id,
    'key' => $secret_key,
    'status' => 'test'
);
Galen
Good call - fixed that, still getting the same response code though.
Ian Silber
A: 

422 is an error code, which is usually used when the request is valid, but can't be processed for some internal constraint. Look in the body of the response, which probably contains details about what went wrong.

troelskn
+1  A: 

The solution was a missing content-type of 'application/json'.

Here's the working code:

include 'CurlRequest.php';

$key = 'mykeyhere';
$group_id = '1234';

$status = 'Awesome status update';

$curl = new CurlRequest('http://coopapp.com/statuses/update.xml?group_id=' . $group_id . '&key=' . $key);
$curl->exec(array(
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode(array('status' => $status)),
    CURLOPT_HTTPHEADER => array("Content-Type: application/json")
 ));
Ian Silber