I'm not sure if this is a bug or not, but it seems like one. I have a custom service that uses GET with retrieve method, REST server, and only has params as args for the service. The result of calling the service is controller not found. After going through RESTServer.inc where resolveController is located, there is the following logic for determining the $class and $operation:
// 'retrieve' method.
// First path element should be not empty.
if ($method == 'GET' && isset($resource['operations']['retrieve']) && $this->checkNumberOfArguments($pc, $resource['operations']['retrieve']) && !empty($path[0]) && $pc >= 1) {
$class = 'operations';
$operation = 'retrieve';
}
This if condition fails and $class stays FALSE. When the method returns, $class is still FALSE and results in $controller = FALSE and eventually controller not found error. The if statement is TRUE for all parts except the call to checkNumberOfArguments. So I looked into checkNumberOfArguments for my service call that isn't working, and also with a service call that is working to see what was different. Here is checkNumberOfArguments function for reference:
/**
* Count possible numbers of 'path' arguments of the method.
*/
private function checkNumberOfArguments($args_number, $resource_operation, $required_args = 0) {
$not_required_args = 0;
if (isset($resource_operation['args'])) {
foreach ($resource_operation['args'] as $argument) {
if (is_array($argument['source']) && isset($argument['source']['path'])) {
if (!empty($argument['optional'])) {
$not_required_args++;
}
else {
$required_args++;
}
}
}
}
return $args_number >= $required_args && $args_number <= $required_args + $not_required_args;
}
What I have found is that when the service only defines param arguments, the checkNumberOfArguments function will always return FALSE when called without the 3rd parameter for $required_args. Since $required_args = 0, and after the loop finishes in checkNumberOfArguments, $not_required_args = 0, then the conditional return statement always evaluates to FALSE.
So, I can fix my service call problem by inserting a dummy path argument which satisfies checkNumberOfArguments, but I'm wondering if that is the right solution. Is it ok for a service to only have param-style args or should every service define at least one path element? If that's the case, then I just need to update the service, and remember that for the future. If that's not the case, then I guess the logic needs to be adjusted in checkNumberOfArguments or possibly in resolveController.
Hopefully I've provided enough information. If not, ask for clarification, and I'll provide it.
Comments
Comment #1
kylebrowning commentedThis a bug, and we should probably write a test for it so we can fix it.
This seems like enough information but Im not able to work on this today so itll have to wait from my perspective.
Feel free to submit a patch otherwise ill whip one up soon.
Comment #2
kylebrowning commentedEDIT: hit the submit button twice, whoops.
Comment #3
flapsjack commentedWithout knowing the project in its entirety, is it enough to add a check for param in addition to path in checkNumberOfArguments? For example:
If this is enough, then how do you access a service without any path args, and how do you specify the output format? Does this open up more questions than first thought?
Comment #4
kylebrowning commentedUpon further review This is incorrect.
You should always have at least 1 path argument.
Use something like actions or target_actions or relationships to achieve what it seems like you want, even index.
Retrieve is specifically for URLS that look like ENDPOINT/RESOURCE/someindexvalue
as an example
api/node/56