I'm writing an iPhone app that accesses my Drupal 6 Services remotely.
I'm using the Cocoa XML-RPC Framework and no matter how I send the arguments to my Drupal site, it returns with "Missing Required Arguments" Fault Error.
I'm using sessions and not keys, and the system.connect method works perfectly and gives me a session Id. But when I try and run any other method that uses arguments it faults...
I know there is not much you can help with such little info, so I guess my real question to the group is how to debug this and figure out why I can't get this working... I'm at my wits end. I have NSLogged the XML for the request and it looks perfect, although I'm curious how sensitive the data types are in Drupal's services.
Comments
Forgive me if I ask simple
Forgive me if I ask simple questions, but sometimes it works...
Tried to use the 'standard' Drupal XMLRPC methods (no connect/login required)?
A1. system.listMethods -> an array of method names
A2. system.methodSignature('system.methodSignature') -> an array of return and parameter types
Tried to use the 'standard' Drupal XMLRPC methods with too few, too many, or the wrong parameters?
B1. Missing params: system.methodSignature() -> faultCode: -32602, faultString: 'Server error. Wrong number of method parameters.'
B2. Wrong param type: system.methodSignature(array("uid" => 1)) -> faultCode: -32602, faultString: 'Server error. Invalid method parameters.'
Now for Services XMLRPC:
You logged in right?
C1. system.connect -> the sess_id
C2. user.login(sess_id, name, password) -> the sess_id for the user, I'll call this user_sess_id
C3. example call: user.get(user_sess_id, 1) -> get a result? I do, a struct.
C4. Missing params: user.get(user_sess_id) -> faultCode: 1 (?) faultString: "Missing required arguments."
C5. Wrong param type: user.get(user_sess_id, array('uid' => 1)) -> get a result? I do, a struct.
The logged in user has the right perrmissions, yes? (shouldn't cause your error message, but you never know) For testing purposes you could use uid = 1 I suppose.
For XMLRPC they are, for Services XMLRPC they're not. Not checked that is, so if you send a
<struct>instead of an<int>it won't cause an "Invalid method parameters" error. (See test C5: sending user.get a struct as the second argument, surprisingly got back a result - the right one too) The XMLRPC parser uses the XML received to create data of the right type - a PHP array in the case of my test.P.S. My Services client code is here: http://drupal.org/node/585014#comment-2987512
Hi Joe, I am not sure if this
Hi Joe,
I am not sure if this is relevant here or not but you can also use plist server module to use native plists in your iphone app http://drupal.org/project/plist_server
SumitK
www.sumitk.net
Got it!
Thanks for your help, and sorry about the late response...
Basically I have finally accepted the reality that if you want to use the Services module and their Servers, you have to do some patch work... In my efforts over the last year, I have patched just about every server module and services for them to play fair... Or to play by my rules, which isn't always "by design".
Sending arguments to the XML-RPC Services Server wasn't working as the arguments array wasn't formatted the way the method expected resulting in none of the arguments being found. Therfore the only ones that worked were the ones without arguments like system.connect...
Basically, Objective-C was sending the XML data like so:
Array ( [0] => Array ( [username] => joeweitzel [password] => mypassword [sessid] => b63335b3d65fda87e1347fbfc8063893 ))When it really wanted it like this, in this order, to match the argument structure expected by the method:
Array ( [0] => b63335b3d65fda87e1347fbfc8063893 [1] => joeweitzel [2] => mypassword )XML-RPC + Objective-C/iPhone & Services 6.x-2.2
Add below to line 393 on the services.module file and you can call services with NSMutableDictionary data.
<?php// Argument formatting just in case...
if( isset($args[0]) ) {
if( is_array($args[0]) ) {
$new_args = array();
foreach ($method['args'] as $key => $info ) {
if( isset( $args[0][$info['name']] ) ) {
$new_args[$key] = $args[0][$info['name']];
}
}
$args = $new_args;
}
}
?>
With this addition, you can call your requests like so using the Cocoa XML-RPC framework. Here's getting a specific Views display with arguments:
XMLRPCRequest * request = XMLRPCRequest alloc] initWithHost:[NSURL URLWithString: @"http://mydrupalsite.com/services/xmlrpc";NSMutableDictionary *postParams = [NSMutableDictionary dictionary];
[postParams setObject:@"MyView" forKey:@"view_name"];
[postParams setObject:sessionID forKey:@"sessid"]; // Get sessionID from returned system.connect method...
[postParams setObject:@"page_2" forKey:@"display_id"]; // Doesn't really use the display name, it uses the display type and number.
[postParams setObject:[[NSArray alloc] initWithObjects:@"firstArg", @"secondArg", nil] forKey:@"args"];
[request setMethod:@"views.get" withObject:postParams];
XMLRPCResponse * viewsResponse = [XMLRPCConnection sendSynchronousXMLRPCRequest:request];
NSMutableArray * viewArray = [viewsResponse object];
NSLog( @"\nDATA: \n%@\n", viewArray );
for (id node in viewArray) {
NSString * title = [node valueForKey:@"title"];
NSString * phone = [[node valueForKey:@"field_phone"] objectAtIndex:0];
NSLog( @"The title is %@ and phone is %@", title, phone );
}
Hope this helps others!
Cool idea sumitk with the pList server. iPhone's love pLists, I'll have to give it a try :)