PHP-RPC update 4

This should be the last version of the spec for PHP-RPC, unless somebody has some great feedback with stuff I overlooked. It might need some clarification and better writing here and there, but I think the general idea is there.

The api for the server class currently works the exact same as before, but support for multi-calls has been added. I also added a client class, which is helpful when you surpass the prototyping phase and you need a more decent way to interact with the service.

Example usage:

<?php

    $url = 'http://localhost/~evert/phprpc/server.php';

    require_once 'Sabre/PHPRPC/Client.php';

    $client = new Sabre_PHPRPC_Client($url,'system');

    $data = $client->testingMethod('test');

    print_r($data);

?>

Multi-call example:

<?php

    $url = 'http://localhost/~evert/phprpc/server.php';

    require_once 'Sabre/PHPRPC/Client.php';

    $client = new Sabre_PHPRPC_Client($url,'system');

    $client->startMultiCall();
    $client->testingMethod('test');
    $client->testingMethod2('test');
    $data = $client->execMultiCall();

    print_r($data);

?>

The source can be downloaded from here. I also added the code to a subversion repository.

Here's the updated proposal. Changes have been highlighted.

The proposal (0.3)

Goals

  • Client should be very easy to implement. Server is allowed to be a bit more complex.
  • No duplication of the HTTP protocol. For example, HTTP already provides encryption, redirecting and authentication.
  • PHP 4 and 5 compatibility. (and 6 when it is released).
  • Client and server implementations should be built from the idea 'be strict in what you produce, be liberal in what you accept'

The request

Requests are made using either GET or POST. Both should be accepted. GET is more appropriate for fetching information, whereas POST is used for posting new data. POST has the advantage that it doesn't have any limits in the size of the request and an encoding can be supplied. GET has the advantage that information can be fetched using a one-liner.

When there is no encoding specified, UTF-8 is assumed. Data supplied using POST should be encoded as application/x-www-form-urlencoded (this is how a browser submits data by default).

The method thats called should always be supplied as the 'method' variable. The method can contain periods (.) to separate namespaces like XML-RPC. Arguments can be specified in two ways, and the API documentation should specify what the appropriate way is. The first way is using named arguments, a GET example would be:

http://www.example.org/services/phprpc?method=getUsers&maxItems=20

The method here is getUsers, the named argument is maxItems and its value is 20.

The second way is using a list of arguments, which might be more appropriate in some cases where you want to directly map services and methods from a class on the server to the api. This is also how XML-RPC works.

http://www.example.org/services/phprpc?method=getUsers&arguments[0]=20&arguments[1]=1

The first argument is 20, the second is 1.

Smart servers should use reflection to automatically map named arguments to the actual arguments in a list.

Clients SHOULD supply the version of PHP they are running. This can be either a complete version number, or just the major version (e.g.: 4, 5, 6). Clients should supply this as the phpVersion parameter. If the versionnumber is not supplied, the current stable PHP version is assumed, which is at the time of writing 5.

Clients MAY also supply the version of the PHP-RPC protocol as the 'version' parameter. Currently this is 0.3.

Clients MAY supply a returnClasses parameter. The value for returnClasses is either 0 or 1 and this can tell the server if the client is aware of typed objects that might be sent from the server.

The server

The server MUST allow requests both GET and POST requests. The server MUST treat any incoming text without encoding as UTF-8.

The server SHOULD allow both named arguments and indexed arguments for methods where this is possible.

If the client sent phpVersion the server MUST convert the returned serialized string so it can be read by the server. If the phpVersion is 4 or 5 the server MUST convert all unicode-strings (type U) to binary strings (type s). If the phpVersion is 4 the server MUST convert all private and protected properties to public properties.

Servers SHOULD also convert all typed objects to either STDClass'es or arrays when the client supplied returnClasses is set to 0, if this is appropriate.

The return data is always in PHP's serialize data format. The Content-Type header should always be 'application/x-php-serialized'

The server will always return an error with the following properties:

result
The actual return data.. (or an array with information about an exception, in which case it should have at least the 'message' property.)
status
HTTP status code for the method call. (200 = success, 500 = internal server error, 400 = bad request, etc etc.) Custom error codes have to start at 600.
version
optional: PHP-RPC protocol version. Currently this is 0.3
server
optional: Name of the server. Can be any string.

Multicall

Servers should be able to parse multi-call requests. This allows a client to wrap multiple methodcalls into one http-request. Multi-call only works with arguments specified as sequences.

Making a multicall is simple, instead of supplying the method as a string, it should be specified as an array with 1 or more methodnames. Arguments are also wrapped in an array (which then contains multiple arrays per method.)

The 'result' key in the response structure will also have to be an array. Each item in this array contains a at least a 'status' and a 'result' property, which have the same meaning as in the main result structure.

This means the status of the entire call can be 200 (success), while the individual responses to methods can contain an error code. The top-level status code will only be an error if the actual request was somehow malformed, and the server couldn't process the individual requests.