Last updated February 24, 2011. Created by bsenftner on February 23, 2011.
Log in to edit this page.
The following demonstrates how to communicate with a remote API implemented as a Services 3.0 REST resource using standard Drupal authentication (login/logout, user's account roles define user's permissions.) In a RESTful API, there is at least one "resource" defined, where each "resource" is something able to support operations in the CRUD pattern: Create, Retrieve, Update, Delete and Index (get a listing). Typically, a RESTful API implements a series of resources, each of which can have instances created, retrieved, updated and deleted. Aside from the necessity of logging in for authentication, most of what one can do within a RESTful API can be handled through one of five routines: Create(), Get(), Update(), Delete() and Index(). The code presented is a PHP object definition for managing communications with a remote API, primarily handled through routines supporting CRUD operations.
There are two example PHP objects defined here, each supporting the same logic, but for different environments. The first example demonstrates how to communicate with a remote API outside of Drupal (without the Drupal API); this is useful for remote API users who are not Drupal based. The second example demonstrates how to communicate with a remote API using Drupal's API. The Drupal API version uses fewer resources, which may matter to some people. And finally, some sample usage of the remote API communication objects is given. The logic is the same, regardless of using the non-Drupal version or the Drupal version.
Using CURL to communicate with a RESTful API
<?php
// *****************************************************************************************
// defines an object for working with a remote API, not using Drupal API
class RemoteAPI {
public $gateway;
public $apiVersion;
public $status;
public $session; // the session name (obtained at login)
public $sessid; // the session id (obtained at login)
const RemoteAPI_status_unconnected = 0;
const RemoteAPI_status_loggedin = 1;
// *****************************************************************************
public function __construct( $gateway, $apiVersion ) {
$this->gateway = $gateway;
$this->apiVersion = $apiVersion;
$this->status = RemoteAPI_status_unconnected;
$this->session = '';
$this->sessid = '';
}
// *****************************************************************************
// after login, the string generated here needs to be included in any http headers,
// under the key 'Cookie':
private function GetCookieHeader() {
return $this->session.'='.$this->sessid;
}
// *****************************************************************************
// return the standard set of curl options for a POST
private function GetCurlPostOptions( $url, $data, $includeAuthCookie = false ) {
$ret = array( CURLOPT_URL => $url,
CURLOPT_FAILONERROR => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 4,
CURLOPT_HTTPHEADER => array('Accept: application/json'),
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $data,
);
if ($includeAuthCookie) {
$ret[CURLOPT_COOKIE] = $this->GetCookieHeader();
}
return $ret;
}
// *****************************************************************************
// return the standard set of curl options for a GET
private function GetCurlGetOptions( $url, $includeAuthCookie = false ) {
$ret = array( CURLOPT_URL => $url,
CURLOPT_FAILONERROR => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_BINARYTRANSFER => 1,
CURLOPT_TIMEOUT => 3,
CURLOPT_HTTPHEADER => array('Accept: application/json'),
);
if ($includeAuthCookie) {
$ret[CURLOPT_COOKIE] = $this->GetCookieHeader();
}
return $ret;
}
// *****************************************************************************
// return the standard set of curl options for a PUT
private function GetCurlPutOptions( $url, $data, $includeAuthCookie = false ) {
$ret = array( CURLOPT_URL => $url,
CURLOPT_FAILONERROR => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => array('Content-Length: ' . strlen($data),
'Accept: application/json'),
CURLOPT_POSTFIELDS => $data,
);
if ($includeAuthCookie) {
$ret[CURLOPT_COOKIE] = $this->GetCookieHeader();
}
return $ret;
}
// *****************************************************************************
// return the standard set of curl options for a DELETE
private function GetCurlDeleteOptions( $url, $includeAuthCookie = false ) {
$ret = array( CURLOPT_URL => $url,
CURLOPT_FAILONERROR => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3,
CURLOPT_HTTPHEADER => array('Accept: application/json'),
CURLOPT_CUSTOMREQUEST => 'DELETE',
);
if ($includeAuthCookie) {
$ret[CURLOPT_COOKIE] = $this->GetCookieHeader();
}
return $ret;
}
// *****************************************************************************
// return false if we're logged in
private function VerifyUnconnected( $caller ) {
if ($this->status != RemoteAPI_status_unconnected) {
return false;
}
return true;
}
// *****************************************************************************
// return false if we're not logged in
private function VerifyLoggedIn( $caller ) {
if ($this->status != RemoteAPI_status_loggedin) {
return false;
}
return true;
}
// *****************************************************************************
// replace these 'resourceTypes' with the names of your resourceTypes
private function VerifyValidResourceType( $resourceType ) {
switch ($resourceType) {
case 'project':
case 'image':
case 'thingy':
return true;
default: return false;
}
}
// *****************************************************************************
// Perform the common logic for performing an HTTP request with cURL
// return an object with 'response', 'error' and 'info' fields.
private function CurlHttpRequest( $caller, $url, $method, $data, $includeAuthCookie = false ) {
$ch = curl_init(); // create curl resource
switch ($method) {
case 'POST': curl_setopt_array($ch, $this->GetCurlPostOptions($url,$data, $includeAuthCookie)); break;
case 'GET': curl_setopt_array($ch, $this->GetCurlGetOptions($url, $includeAuthCookie)); break;
case 'PUT': curl_setopt_array($ch, $this->GetCurlPutOptions($url, $data, $includeAuthCookie)); break;
case 'DELETE': curl_setopt_array($ch, $this->GetCurlDeleteOptions($url, $includeAuthCookie)); break;
default:
return NULL;
}
$ret = new stdClass;
$ret->response = curl_exec($ch); // execute and get response
$ret->error = curl_error($ch);
$ret->info = curl_getinfo($ch);
curl_close($ch);
if ($ret->info['http_code'] == 200) {
$ret->response = json_decode($ret->response);
}
return $ret;
}
// *****************************************************************************
// Login: uses the cURL library to handle login
public function Login( $username, $password ) {
$callerId = 'RemoteAPI->Login';
if (!$this->VerifyUnconnected( $callerId )) {
return NULL; // error
}
$url = $this->gateway.$this->apiVersion.'/user/login';
$data = array( 'username' => $username, 'password' => $password, );
$data = http_build_query($data, '', '&');
$ret = $this->CurlHttpRequest($callerId, $url, 'POST', $data, false);
if ($ret->info['http_code'] != 200) {
return NULL;
}
else {
$this->sessid = $ret->response->sessid;
$this->session = $ret->response->session_name;
$this->status = RemoteAPI_status_loggedin;
return true; // success!
}
} // end of Login() definition
// *****************************************************************************
// Logout: uses the cURL library to handle logout
public function Logout() {
$callerId = 'RemoteAPI->Logout';
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
$url = $this->gateway.$this->apiVersion.'/user/logout';
$ret = $this->CurlHttpRequest($callerId, $url, 'POST', NULL, true);
if ($ret->info['http_code'] != 200) {
return NULL;
}
else {
$this->status = RemoteAPI_status_unconnected;
$this->sessid = '';
$this->session = '';
return true; // success!
}
} // end of Login() definition
// **************************************************************************
// perform an 'Index' operation on a resource type using cURL.
// Return an array of resource descriptions, or NULL if an error occurs
public function Index( $resourceType ) {
$callerId = 'RemoteAPI->Index';
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType;
$ret = $this->CurlHttpRequest($callerId, $url, 'GET', NULL, true);
return $ret->response;
}
// *****************************************************************************
// create a new resource of the named type given an array of data, using cURL
public function Create( $resourceType, $resourceData ) {
$callerId = 'RemoteAPI->Create: "'.$resourceType;
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
if (!$this->VerifyValidResourceType($resourceType)) {
return NULL;
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType;
$data = http_build_query($resourceData, '', '&');
$ret = $this->CurlHttpRequest($callerId, $url, 'POST', $data, true);
return $ret->response;
}
// **************************************************************************
// perform a 'GET' operation on the named resource type and id using cURL.
public function Get( $resourceType, $resourceId ) {
$callerId = 'RemoteAPI->Get: "'.$resourceType.'/'.$resourceId.'"';
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
if (!$this->VerifyValidResourceType($resourceType)) {
return NULL;
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType.'/'.$resourceId;
$ret = $this->CurlHttpRequest($callerId, $url, 'GET', NULL, true);
return $ret->response;
}
// *****************************************************************************
// update a resource given the resource type and updating array, using cURL.
public function Update( $resourceType, $resourceData ) {
$callerId = 'RemoteAPI->Update: "'.$resourceType;
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
if (!$this->VerifyValidResourceType($resourceType)) {
return NULL;
}
if (!isset($resourceData['data']['id'])) {
return NULL;
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType.'/'.$resourceData['data']['id'];
$data = http_build_query($resourceData, '', '&');
$ret = $this->CurlHttpRequest($callerId, $url, 'PUT', $data, true);
return $ret->response;
}
// *****************************************************************************
// perform a 'DELETE' operation on the named resource type and id using cURL
public function Delete( $resourceType, $resourceId ) {
$callerId = 'RemoteAPI->Delete: "'.$resourceType;
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
if (!$this->VerifyValidResourceType($resourceType)) {
return NULL;
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType.'/'.$resourceId;
$ret = $this->CurlHttpRequest($callerId, $url, 'DELETE', NULL, true);
return $ret->response;
}
} // end of RemoteAPI object definition using cURL and not Drupal API
?>Using the Drupal API to communicate with a RESTful API
<?php
// *****************************************************************************************
// defines an object for working with the remote API, using the Drupal API
class RemoteAPI_via_DrupalAPI {
public $gateway;
public $apiVersion;
public $status;
public $session; // the session name (obtained at login)
public $sessid; // the session id (obtained at login)
const RemoteAPI_status_unconnected = 0;
const RemoteAPI_status_loggedin = 1;
// *****************************************************************************
public function __construct( $gateway, $apiVersion ) {
$this->gateway = $gateway;
$this->apiVersion = $apiVersion;
$this->status = RemoteAPI_status_unconnected;
$this->session = '';
$this->sessid = '';
}
// *****************************************************************************
// after login, the string generated here needs to be included in any http headers,
// under the key 'Cookie':
private function GetCookieHeader() {
return $this->session.'='.$this->sessid;
}
// *****************************************************************************
// return false if we're logged in
private function VerifyUnconnected( $caller ) {
if ($this->status != RemoteAPI_status_unconnected) {
return false;
}
return true;
}
// *****************************************************************************
// return false if we're not logged in
private function VerifyLoggedIn( $caller ) {
if ($this->status != RemoteAPI_status_loggedin) {
return false;
}
return true;
}
// *****************************************************************************
// replace these with the resource type names you'll be using
private function VerifyValidResourceType( $resourceType ) {
switch ($resourceType) {
case 'project':
case 'image':
case 'thingamajig':
return true;
default: return false;
}
}
// *****************************************************************************
// Perform the common logic for performing an HTTP request with the Drupal API
public function DrupalHttpRequest( $caller, $url, $method, $data, $includeAuthCookie = false ) {
$headers = array();
$headers['Content-Type'] = 'application/x-www-form-urlencoded';
if ($includeAuthCookie) {
$headers['Cookie'] = $this->GetCookieHeader();
}
if ($data) {
$data = http_build_query($data, '', '&');
}
$response = drupal_http_request($url, $headers, $method, $data);
if ($response->code == 200) {
$response->data = json_decode($response->data);
}
else {
$response->data = NULL;
}
return $response;
}
// *****************************************************************************
public function Login( $username, $password ) {
$callerId = 'RemoteAPI_DrupalAPI->Login';
if (!$this->VerifyUnconnected( $callerId )) {
return NULL; // error
}
$url = $this->gateway.$this->apiVersion.'/user/login';
$data = array( 'username' => $username, 'password' => $password, );
$response = $this->DrupalHttpRequest($callerId, $url, 'POST', $data, false);
if ($response->code == 200) {
$this->session = $response->data->session_name;
$this->sessid = $response->data->sessid;
$this->status = RemoteAPI_status_loggedin;
return true; // meaning okay
}
return NULL; // meaning error
}
// *****************************************************************************
public function Logout() {
$callerId = 'RemoteAPI_DrupalAPI->Logout';
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
$url = $this->gateway.$this->apiVersion.'/user/logout';
$response = $this->DrupalHttpRequest($callerId, $url, 'POST', NULL, true);
if ($response->code == 200) {
$this->status = RemoteAPI_status_unconnected;
$this->sessid = '';
$this->session = '';
return true; // success!
}
return NULL;
}
// **************************************************************************
// perform an 'Index' operation on a resource type using Drupal API.
// Return an array of resource descriptions, or NULL if an error occurs
public function Index( $resourceType ) {
$callerId = 'RemoteAPI_DrupalAPI->Index';
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType;
$response = $this->DrupalHttpRequest($callerId, $url, 'GET', NULL, true);
return $response->data; // if failed, this is NULL, if success, this is an object holding requested data
}
// *****************************************************************************
// create a new resource of the named type given an array of data, using Drupal API
public function Create( $resourceType, $resourceData ) {
$callerId = 'RemoteAPI_DrupalAPI->Create:'.$resourceType;
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
if (!$this->VerifyValidResourceType($resourceType)) {
return NULL;
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType;
$response = $this->DrupalHttpRequest($callerId, $url, 'POST', $resourceData, true);
return $response->data; // if failed, this is NULL, if success, this is an object holding response data
}
// **************************************************************************
// perform a 'GET' operation on the named resource type and id using Drupal API
public function Get( $resourceType, $resourceId ) {
$callerId = 'RemoteAPI_DrupalAPI->Get:'.$resourceType.'/'.$resourceId.'"';
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
if (!$this->VerifyValidResourceType($resourceType)) {
return NULL;
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType.'/'.$resourceId;
$response = $this->DrupalHttpRequest($callerId, $url, 'GET', NULL, true);
return $response->data; // if failed, this is NULL, if success, this is an object holding response data
}
// *****************************************************************************
// update a resource given the resource type and updating array, using Drupal API
public function Update( $resourceType, $resourceData ) {
$callerId = 'RemoteAPI_DrupalAPI->Update:'.$resourceType;
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
if (!$this->VerifyValidResourceType($resourceType)) {
return NULL;
}
if (!isset($resourceData['data']['id'])) {
_devReport('missing referencing ID of update resource!');
return NULL;
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType.'/'.$resourceData['data']['id'];
$response = $this->DrupalHttpRequest($callerId, $url, 'PUT', $resourceData, true);
return $response->data; // if failed, this is NULL, if success, this is an object holding response data
}
// *****************************************************************************
// perform a 'DELETE' operation on the named resource type and id using Drupal API
public function Delete( $resourceType, $resourceId ) {
$callerId = 'RemoteAPI_DrupalAPI->Delete:'.$resourceType;
if (!$this->VerifyLoggedIn( $callerId )) {
return NULL; // error
}
if (!$this->VerifyValidResourceType($resourceType)) {
return NULL;
}
$url = $this->gateway.$this->apiVersion.'/'.$resourceType.'/'.$resourceId;
$response = $this->DrupalHttpRequest($callerId, $url, 'DELETE', NULL, true);
return $response->data; // if failed, this is NULL, if success, this is an object holding response data
}
} // end of RemoteAPI_via_DrupalAPI object definition
?>Example usage of communicating with a remote API
<?php
// create a new API communications object like this:
// the two parameters compose the URL the API communications take place
// (they are separate to facilitate API gateways and different API versions)
$apiObj = new RemoteAPI_DrupalAPI( 'http://api-project-clientName.apigee.com', // gateway
'/clientName/api/dev' // Services end point
);
// here's the logic to login. Required for authentication, and all other operations:
$apiObj->Login( 'joeuser', 'XXXXXXX' ); // pass in username and password
// if a resource type called "project" existed, a new project could be created like this:
$data = array( 'data' => array( 'title' => 'ApiDefinedProject',
'status' => 'active', // fantasy fields
'body' => 'demo information',
'comments' => 'disabled',
'tags' => '',
),
);
$ret = $apiObj->Create('project', $data );
// $ret will be NULL if an error occured, or will be an object with an 'id' field
// retrieve our new project:
$ret = $apiObj->Get('project', $ret->id); // <- 'id' used to get new project
// modifying the data for a modify:
$data['data']['body'] .= " can be modified too";
$data['data']['id'] = $ret->id; // <- so Update() knows what to modify
$ret = $apiObj->Update('project', $data );
// and delete just needs the id:
$ret = $apiObj->Delete('project', $ret->id );
// when completed working with the API, logout like this:
$apiObj->Logout();
?>
Comments
I couldn't get this working with Drupal 7
Hello,
I just tried this against a Drupal 7 install and I get 200 as a response code but nothing in the response piece of the array so I get no session id returned:
Class Object
(
[response] =>
[error] =>
[info] => Array
(
[url] => http://drupalwebsvcstest.babson.edu/drupal7/user/login
[content_type] => text/html; charset=utf-8
[http_code] => 200
[header_size] => 435
[request_size] => 202
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.140793
[namelookup_time] => 0.000237
[connect_time] => 0.000328
[pretransfer_time] => 0.00033
[size_upload] => 34
[size_download] => 8689
[speed_download] => 61714
[speed_upload] => 241
[download_content_length] => -1
[upload_content_length] => 0
[starttransfer_time] => 0.127042
[redirect_time] => 0
[certinfo] => Array
(
)
)
)
Are we sure this works with Drupal 7 ? I really wish the Oauth module worked with Drupal 7. Any help on this would be great. Thanks.
This was written and tested
This was written and tested in Services 3.0 for Drupal 6 - but the essential logic is the same.
You say you're getting a 200 response code - which means it is working somewhere, you're just not getting your session data back. Are you in control the the site with Services 3.0 installed? You should be able to add debugging logic to see where your data is being dropped...
(You did visit the Services configuration pages and enable the "user" resource's login and logout APIs for use, right?)
-Blake
www.BlakeSenftner.com www.MissingUbercartManual.com www.cg-general-store.com www.droplabs.net
Thanks I got this code working with Drupal 7
same as what you were doing, but it was easier for me to understand my own code I wrote, I can put it in classes later. thanks for your posts. I guess curl can do a lot more than I knew.
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"http://drupal_base_url/drupal7/user/login");
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'PHP script');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIEJAR, "cookie.txt");
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "name=username&pass=password&form_id=user_login");
curl_exec ($ch);
curl_setopt($ch, CURLOPT_URL,"http://drupal_base_url/test_endpoint/users");
curl_setopt($ch, CURLOPT_HTTPGET, 1);
curl_exec ($ch);
curl_close ($ch);
unset($ch);
?>
See my blog for a full post of my code which returns just json which is more useful: http://www.barnettech.com/drupal7_services_curl_rest_api
This creates a user using curl but a question for you
http://www.barnettech.com/content/drupal-7-create-user-using-rest-and-curl
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"http://base_url/user/login");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, 'PHP script');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIEJAR, "cookie.txt");
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "name=username&pass=password&form_id=user_login");
ob_start(); //dont print out this output
curl_exec ($ch);
curl_setopt($ch, CURLOPT_URL,"http://base_url/test_endpoint/users");
//curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
//curl_setopt($ch, CURLOPT_HTTPGET, 1);
ob_end_clean(); //resume printout output to screen
/*if ($ret->info['http_code'] == 200) {
$ret->response = json_decode($ret->response);
}*/
//print_r($ret);
curl_setopt($ch, CURLOPT_POST, 1);
//curl_setopt($ch, CURLOPT_FAILONERROR, true);
//curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resourceData = array( 'account' => array('username' => 'jbarnett',
'name' => 'jbarnett',
'pass' => 'xxxxxx',
'mail' => 'username@yahoo.com',
),
);
$data2 = http_build_query($resourceData, '', '&');
curl_setopt($ch, CURLOPT_POSTFIELDS, "account=".$data2);
$ret = new stdClass;
$ret->response = curl_exec($ch); // execute and get response
$ret->error = curl_error($ch);
$ret->info = curl_getinfo($ch);
/*if ($ret->info['http_code'] == 200) {
$ret->response = json_decode($ret->response);
}*/
print $ret->response;
print $ret->error;
curl_close ($ch);
unset($ch);
?>
One thing: it throws away the first element 'username' in this array, hence I just put in a bogus element -- username -- , as you know name is the element name in fact (I'm still looking at why it's doing this):
$resourceData = array( 'account' => array('username' => 'jbarnett',
'name' => 'jbarnett',
'pass' => 'xxxxxx',
'mail' => 'username@yahoo.com',
),
);
Is this a bug that the first element of the array is thrown away
I'm seeing the same thing for update statements. The first element of the array is thrown away.
I had to put this in to make it work:
$resourceData = array( 'throwaway' => array('mail' => 'test'),
'data' => array(
'mail' => 'testmail@yahoo.com',
),
);
$data2 = http_build_query($resourceData, '', '&');
Then I ran curl_exec (with all the right options for curl_setop)
I created the user but is this a bug with the services module that it always throws up the first element of the array?
My full code which successfully updates a user using rest, services and curl is here: http://www.barnettech.com/content/drupal-7-update-user-using-rest-curl-a...
I noticed strange behavior
I noticed strange behavior with the data parameters myself, and came to the conclusion that the post data needed a 'double wrapper'. If you look at my code example of usage (from above, but duplicated here:)
<?php$data = array( 'data' => array( 'title' => 'ApiDefinedProject',
'status' => 'active', // fantasy fields
'body' => 'demo information',
'comments' => 'disabled',
'tags' => '',
),
);
?>
Notice how the data is actually in $data['data'] rather than just in $data? I found this was necessary to get my parameters into my logic on the other side of Services.
Note that this issue should be brought up in the Services issue queue. I think it's a matter of documentation - simply let us know what is the right way do pass in data. Right now, only the module itself and old examples are available.
-Blake
www.BlakeSenftner.com www.MissingUbercartManual.com www.cg-general-store.com www.droplabs.net
Thanks so much for your great articles. Could do do me a favor?
Thanks so much for your great articles,it is really very useful for me .I'm using your drupal Api to post a comment to node 2,
my test code is :
$apiObj = new RemoteAPI_via_DrupalAPI( 'http://localhost:8888', '/fhxmt/rest' );
$apiObj->Login( 'username, 'password' ); // pass in username and password
$data = array("data"=>array(
"nid" => "2",
"comment_body" =>
array(
"und" => array(
"0" => array( "value" => "555 anonymous need to be approved? ")
)
)
)
);
$ret = $apiObj->Create('comment.create', $data );
$apiObj->Logout();
I can Login and Logout successfully. But I can't post the comment ,the response is alway something like :
"HTTP/1.0 401 Unauthorized: Missing required argument comment" ,I think the format of my $data array must be wrong.
Could you please give me some guidelines ?
ps.
I can use
$data = array(
"nid" => "2",
"comment_body" =>
array(
"und" => array(
"0" => array( "value" => "555 anonymous need to be approved? ")
)
)
);
to post the comments successfully in xmlrpc service.
zhou bin
Sorry; I have not
Sorry; I have not experimented with standard Drupal comments, so I don't have any useful advice. Due to the lack of documentation, and the lack of step-by-step debugging of PHP, I use the Devel Module's dsm() and dpm() routines, sprinkled through the Services Module's source code to painfully and "time consumingly" figure it out.
Drupal comments themselves are 'non-standard' enough that I've not bothered to figure them out for programmatic operations. I'll need to soon, so an update may occur to this documentation after that. (I need to programmatically update comments by the end of September, 2011.)
-Blake
www.BlakeSenftner.com www.MissingUbercartManual.com www.cg-general-store.com www.droplabs.net
Should this be added to your great document?
I forget something, in order to get Login and Logout work ,I Have to add
$headers['Accept'] = 'application/json';
to the DrupalHttpRequest method, should this be added to your great document?
zhou bin
Which version of Services are
Which version of Services are you running? I've been using the above code, pretty much unaltered, for months. I just noticed a new Release Candidate for Services 3.0 is out, and perhaps if you're on that and I'm not yet, that's a key difference?
-Blake
www.BlakeSenftner.com www.MissingUbercartManual.com www.cg-general-store.com www.droplabs.net
True, if you have not enabled x-www-form-urlencoded
If you haven't enabled application/x-www-form-urlencoded request parsing in the services server definition page, you need to do this. You'll also need to json_encode() the value you use for CURLOPT_POSTFIELDS.
Sample code eats server response in error conditions
One problem with this code, if the server produces an error, the HTTP response body is tossed out. Typically when dealing with a RESTful server the response body contains some interesting info on the error, possibly to show the user.
You'll need to change CURLOPT_FAILONERROR to false if you want the response body to come back when your call produces an error.