JSON RPC Server & Client

Setup the JSON RPC Server

Assuming you want to use the provided interop-factories, let’s start with a sample configuration:

A sample configuration might look like this, more details and explanation will be in the coming chapters.

return [
    'dependencies' => [
        'factories' => [
            Driver::class => Container\DriverFactory::class,
            'default-amqp-connection' => [Container\ConnectionFactory::class, 'default'],
            'demo-rpc-server' => [Container\JsonRpcServerFactory::class, 'demo-rpc-server'],
            'timestwo' => function () {
                return function (\Humus\Amqp\JsonRpc\Request $request): \Humus\Amqp\JsonRpc\Response {
                    return \Humus\Amqp\JsonRpc\JsonRpcResponse::withResult($request->id(), $request->params() * 2);
                };
            },
        ],
    ],
    'humus' => [
        'amqp' => [
            'driver' => 'amqp-extension',
            'exchange' => [
                'demo-rpc-server' => [
                    'name' => 'demo-rpc-server',
                    'type' => 'direct',
                    'connection' => 'default-amqp-connection',
                ],
            ],
            'queue' => [
                'demo-rpc-server' => [
                    'name' => 'demo-rpc-server',
                    'exchanges' => [
                        'demo-rpc-server' => [],
                    ],
                    'connection' => 'default-amqp-connection',
                ],
            ],
            'connection' => [
                'default-amqp-connection' => [
                    'host' => 'localhost',
                    'port' => 5672,
                    'login' => 'guest',
                    'password' => 'guest',
                    'vhost' => '/',
                    'persistent' => true,
                    'read_timeout' => 3, //sec, float allowed
                    'write_timeout' => 1, //sec, float allowed
                ],
            ],
            'json_rpc_server' => [
                'demo-rpc-server' => [
                    'delivery_callback' => 'timestwo',
                    'idle_timeout' => 10,
                    'queue' => 'demo-rpc-server',
                    'auto_setup_fabric' => true,
                ],
            ],
        ],
    ],
];

So what’s important here? The JSON RPC Server needs an exchange and a queue. All messages routed to the exchange, will get routed to the server queue. In this example we use a direct exchange and a single queue for the server. This is pretty much the simplest setup we can have.

The second this is, the server needs a callback, we use timestwo here. As you can see in the dependencies setup, the callback is simply turning a Request into a Response like this:

function (\Humus\Amqp\JsonRpc\Request $request): \Humus\Amqp\JsonRpc\Response {
    return \Humus\Amqp\JsonRpc\JsonRpcResponse::withResult($request->id(), $request->params() * 2);
}

For the callback function consider this:

  • Return an instance of HumusAmqpJsonRpcResponse
  • Just return some value, the server will automatically wrap the result with an instance of HumusAmqpJsonRpcJsonRpcResponse
  • All thrown exceptions will return an error response to the client

The HumusAmqpJsonRpcRequest also has a method named method() - this allows you to a single callback to return different results, based on the method. For example:

function (\Humus\Amqp\JsonRpc\Request $request): \Humus\Amqp\JsonRpc\Response {
    switch ($request->method()) {
        case 'times2':
            return \Humus\Amqp\JsonRpc\JsonRpcResponse::withResult($request->id(), $request->params() * 2);
        case 'times3:
            return \Humus\Amqp\JsonRpc\JsonRpcResponse::withResult($request->id(), $request->params() * 3);
        case 'plus5':
            return \Humus\Amqp\JsonRpc\JsonRpcResponse::withResult($request->id(), $request->params() + 5);
        default:
            return \Humus\Amqp\JsonRpc\JsonRpcResponse::withError($request->id(), new \Humus\Amqp\JsonRpc\JsonRpcError(32601));
    }
}

Running JSON-RPC servers

To start a JSON-RPC server

$ ./vendor/bin/humus-amqp json_rpc_server -n demo-rpc-server -a 100

This will start the demo-rpc-server and consume 100 messages until it stops or times out.

Setup the JSON RPC Client

Again, let’s start with a sample configuration first (and skip the server config part, to make it easier to read):

return [
    'dependencies' => [
        'factories' => [
            Driver::class => Container\DriverFactory::class,
            'default-amqp-connection' => [Container\ConnectionFactory::class, 'default'],
            'demo-rpc-client' => [Container\JsonRpcClientFactory::class, 'demo-rpc-client'],
        ],
    ],
    'humus' => [
        'amqp' => [
            'driver' => 'amqp-extension',
            'exchange' => [
                'demo-rpc-client' => [
                    'name' => 'demo-rpc-client',
                    'type' => 'direct',
                    'connection' => 'default-amqp-connection',
                ],
            ],
            'queue' => [
                'demo-rpc-client' => [
                    'name' => '',
                    'exchanges' => [
                        'demo-rpc-client' => [],
                    ],
                    'connection' => 'default-amqp-connection',
                ],
            ],
            'connection' => [
                'default-amqp-connection' => [
                    'host' => 'localhost',
                    'port' => 5672,
                    'login' => 'guest',
                    'password' => 'guest',
                    'vhost' => '/',
                    'persistent' => true,
                    'read_timeout' => 3, //sec, float allowed
                    'write_timeout' => 1, //sec, float allowed
                ],
            ],
            'json_rpc_client' => [
                'demo-rpc-client' => [
                    'queue' => 'demo-rpc-client',
                    'auto_setup_fabric' => true,
                    'exchanges' => [
                        'demo-rpc-server'
                    ],
                ],
            ],
        ],
    ],
];

So what’s important here: The RPC client also needs an exchange and a queue. But the important thing to note is, that the queue has no name, an empty string is given as queue name. This will automatically create a queue with a unique name that will get destroyed, when the client is no longer in use. Also the client needs an array of exchanges, where the client can send messages to. In this example we use a single exchange demo-rpc-server.

Using the JSON RPC client

As an exercise, let’s send two requests to our JSON RPC server and see what results we get:

$request1 = new \Humus\Amqp\JsonRpc\JsonRpcRequest('demo-rpc-server', 'timestwo', 1, 'request-1');
$request2 = new \Humus\Amqp\JsonRpc\JsonRpcRequest('demo-rpc-server', 'timestwo', 2, 'request-2');

$client->addRequest($request1);
$client->addRequest($request2);

$responses = $client->getResponseCollection();

$response1 = $responses->getResponse('request-1');
$response2 = $responses->getResponse('request-2');

var_dump($response1->isError()); // false
var_dump($response2->isError()); // false

var_dump($response1->result()); // 2
var_dump($response2->result()); // 4

Troubleshooting

If you have read this guide and still have issues with connecting, check our Troubleshooting guide and feel free to raise an issue at Github.

Tell Us What You Think!

Please take a moment to tell us what you think about this guide: Send an e-mail, say hello in the HumusAmqp gitter chat. or raise an issue on Github.

Let us know what was unclear or what has not been covered. Maybe you do not like the guide style or grammar or discover spelling mistakes. Reader feedback is key to making the documentation better.