Import the main routing file or create a custom route:
# config/routes.yaml
rpc:
resource: '@NanofelisJsonRpcBundle/Resources/config/routing.xml'
or
# config/routes.yaml
rpc:
path: /
controller: nanofelis_json_rpc.action.rpc
methods: POST
rpc_doc:
path: /doc
controller: nanofelis_json_rpc.action.doc
methods: GET
Simply Tag the services you want to expose and send a json-rpc payload to the RPC endpoint.
The method parameter must follow the convention {serviceKey}.{method}
# config/services.yaml
App\RpcServices:
resource: src/RpcServices
tag: ['nanofelis_json_rpc']
namespace App\RpcServices;
use Nanofelis\JsonRpcBundle\Service\AbstractRpcService;
class MyService extends AbstractRpcService
{
public static function getServiceKey(): string
{
return 'myService';
}
function add(int $a, int $b): int
{
return $a + $b;
}
}
# Example call with success response
curl -d '{"jsonrpc": "2.0", "method": "myService.add", "params": [1, 2], "id": "test-call"}' http://localhost | fx this
{
"jsonrpc": "2.0",
"result": 3,
"id": "test-call"
}
# Example call with wrong method parameters
curl -d '{"jsonrpc": 2.0, "method": "myService.add", "params": [1], "id": "test-call"}' http://localhost | fx this
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "invalid params",
"data": null
},
"id": "test-call"
}
Only exceptions that extend the AbstractRpcException.php will be cast to a JSON-RPC error.
As described by the RFC, multiple requests can be sent in a single call.
# Example batch call
curl -d '[{"jsonrpc": "2.0", "method": "myService.add", "params": [1, 2], "id": "test-call-0"}, {"jsonrpc": "2.0", "method": "myService.add", "params": [3, 4], "id": "test-call-0"}]' http://localhost | fx this
[
{
"jsonrpc": "2.0",
"result": 3,
"id": "test-call-0"
},
{
"jsonrpc": "2.0",
"result": 7,
"id": "test-call-1"
}
]
This bundle supports the built-in Argument Resolver from the Symfony Core for RPC methods.
As for a regular controller method, dates and Doctrine entities for example are automatically converted if a parameter's name matches a method argument with the correct type hinting or attribute.
namespace App\RpcServices;
class MyService
{
function workWithEntity(MyEntity $entity, #[MapDateTime(format: 'Y-m-d')] \DateTime $date)
{
//
}
}
```shell script
# Example call with type hinting
curl -d '{'jsonrpc': "2.0", "method": "myService.workWithEntity", "params": ["entity": 1, "date": "2017-01-01"]}' http://localhost
Responses are always processed by a Symfony normalizer. If you need to specify a normalization context, you can use the RpcNormalizationContext
attribute:
namespace App\RpcServices;
use Nanofelis\JsonRpcBundle\Attribute\RpcNormalizationContext;
class MyService
{
#[RpcNormalizationContext(contexts: ['custom'])]
function doSomething($data): Article
{
$article = $this->handler($data);
return $article;
}
}
namespace App\Normalizer;
use App\Entity\Article;
class ArticleNormalizer implements NormalizerInterface
{
public function normalize($vehicle, $format = null, array $context = [])
{
if (in_array('custom', $context) {
...
}
}
public function supportsNormalization($data, $format = null): bool
{
return $data instanceof Article;
}
}
You can hook to the following event in the rpc request lifecycle:
nanofelis_json_rpc.before_method
Event Class: RpcBeforeMethodEvent
This event is dispatched just before the method execution. You can use it to alter the rpc request params.
use Symfony\Component\HttpKernel\Event\ControllerEvent;
public function onRpcBeforeMethod(RpcBeforeMethodEvent $event)
{
$rpcRequest = $event->getRpcRequest();
$serviceDescriptor = $event->getServiceDescriptor();
}