yoanm / jsonrpc-server-sdk
Server SDK to convert a json-rpc request string into json-rpc response string
Installs: 143 488
Dependents: 9
Suggesters: 3
Security: 0
Stars: 5
Watchers: 3
Forks: 3
Open Issues: 3
Requires
- php: ^8.0
- ext-json: *
Requires (Dev)
- behat/behat: ^3.9.0
- coduo/php-matcher: ^6.0
- dvdoug/behat-code-coverage: ^5.0
- phpspec/prophecy: ^1.15
- phpspec/prophecy-phpunit: ^2.0
- phpunit/phpunit: ^9.6
- squizlabs/php_codesniffer: ^3.5
- yoanm/jsonrpc-server-doc-sdk: ^0.3 || ^1.0
- yoanm/php-unit-extended: ^2.0
Suggests
- yoanm/jsonrpc-params-symfony-validator-sdk: Compatible params validator
- yoanm/jsonrpc-server-doc-sdk: Create documentation for your server
- yoanm/symfony-jsonrpc-http-server: JSON-RPC HTTP Symfony server Bundle
This package is auto-updated.
Last update: 2024-10-06 09:20:23 UTC
README
Simple server SDK to convert a json-rpc request string into json-rpc response string.
See yoanm/symfony-jsonrpc-http-server for automatic dependency injection.
See yoanm/jsonrpc-params-symfony-validator-sdk for params validation.
See yoanm/jsonrpc-server-doc-sdk for documentation generation.
How to use
Sdk requires only two things :
- A method resolver : must implements JsonRpcMethodResolverInterface, resolving logic's is your own.
- Methods : JsonRpc methods which implements JsonRpcMethodInterface
Sdk optionally provide :
- Events dispatch
- Params validation
Simple Example
JSON-RPC Method
use Yoanm\JsonRpcServer\Domain\JsonRpcMethodInterface; class DummyMethod implements JsonRpcMethodInterface { /** * {@inheritdoc} */ public function apply(array $paramList = null) { // Handle the request ... // Then return a result return [ 'status' => 'done', ]; // Or return null; // Or return 12345; } }
Array method resolver (simple example)
You can use the one used for behat tests or this Psr11 method resolver as example
use Yoanm\JsonRpcServer\Domain\JsonRpcMethodInterface; use Yoanm\JsonRpcServer\Domain\JsonRpcMethodResolverInterface; class ArrayMethodResolver implements JsonRpcMethodResolverInterface { /** @var JsonRpcMethodInterface[] */ private $methodList = []; /** * {@inheritdoc} */ public function resolve(string $methodName) : ?JsonRpcMethodInterface { return array_key_exists($methodName, $this->methodList) ? $this->methodList[$methodName] : null ; } /** * @param JsonRpcMethodInterface $method * @param string $methodName */ public function addMethod(JsonRpcMethodInterface $method, string $methodName) { $this->methodList[$methodName] = $method; } }
Then add your method to the resolver and create the endpoint :
use Yoanm\JsonRpcServer\App\Creator\ResponseCreator; use Yoanm\JsonRpcServer\App\Handler\ExceptionHandler; use Yoanm\JsonRpcServer\App\Handler\JsonRpcRequestHandler; use Yoanm\JsonRpcServer\App\Serialization\JsonRpcCallDenormalizer; use Yoanm\JsonRpcServer\App\Serialization\JsonRpcCallResponseNormalizer; use Yoanm\JsonRpcServer\App\Serialization\JsonRpcCallSerializer; use Yoanm\JsonRpcServer\App\Serialization\JsonRpcRequestDenormalizer; use Yoanm\JsonRpcServer\App\Serialization\JsonRpcResponseErrorNormalizer; use Yoanm\JsonRpcServer\App\Serialization\JsonRpcResponseNormalizer; use Yoanm\JsonRpcServer\Infra\Endpoint\JsonRpcEndpoint; $resolver = new ArrayMethodResolver(); $resolver->addMethod('dummy-method', new DummyMethod()); $jsonRpcSerializer = new JsonRpcCallSerializer( new JsonRpcCallDenormalizer( new JsonRpcRequestDenormalizer() ), new JsonRpcCallResponseNormalizer( new JsonRpcResponseNormalizer() // Or `new JsonRpcResponseNormalizer(new JsonRpcResponseErrorNormalizer())` for debug purpose // To also dump arguments, be sure 'zend.exception_ignore_args' ini option is not at true/1 ) ); $responseCreator = new ResponseCreator(); $requestHandler = new JsonRpcRequestHandler($resolver, $responseCreator); $exceptionHandler = new ExceptionHandler($responseCreator); $endpoint = new JsonRpcEndpoint($jsonRpcSerializer, $requestHandler, $exceptionHandler);
Once endpoint is ready, you can send it request string :
$requestString = <<<JSONRPC { "jsonrpc": "2.0", "id": 1 "method": "dummy-method" } JSONRPC; $responseString = $endpoint->index($requestString);
$responseString
will be the following string depending of method returned value :
-
{"jsonrpc":"2.0","id":1,"result":{"status":"done"}}
-
{"jsonrpc":"2.0","id":1,"result":null}
-
{"jsonrpc":"2.0","id":1,"result":12345}
Events dispatch example
Simple event dispatcher
You can use the one used for behat tests as example
use Yoanm\JsonRpcServer\Domain\Event\JsonRpcServerEvent; use Yoanm\JsonRpcServer\Domain\JsonRpcServerDispatcherInterface; /** * Class SimpleDispatcher */ class SimpleDispatcher implements JsonRpcServerDispatcherInterface { /** @var callable[] */ private $listenerList = []; /** * {@inheritdoc} */ public function dispatchJsonRpcEvent(string $eventName, JsonRpcServerEvent $event = null) : void { if (!array_key_exists($eventName, $this->listenerList)) { return; } foreach ($this->listenerList[$eventName] as $listener) { $listener($event, $eventName); } } /** * {@inheritdoc} */ public function addJsonRpcListener(string $eventName, $listener) : void { $this->listenerList[$eventName][] = $listener; } }
Then bind your listeners to your dispatcher:
use Yoanm\JsonRpcServer\Domain\Event\Acknowledge\OnRequestReceivedEvent; use Yoanm\JsonRpcServer\Domain\Event\Acknowledge\OnResponseSendingEvent; use Yoanm\JsonRpcServer\Domain\Event\Action\OnMethodSuccessEvent; $dispatcher = new SimpleDispatcher(); $listener = function ($event, $eventName) { echo sprintf( 'Received %s with event class "%s"', $eventName, get_class($event) ); }; $dispatcher->addJsonRpcListener(OnRequestReceivedEvent::EVENT_NAME, $listener); $dispatcher->addJsonRpcListener(OnResponseSendingEvent::EVENT_NAME, $listener); $dispatcher->addJsonRpcListener(OnMethodSuccessEvent::EVENT_NAME, $listener);
And bind dispatcher like following :
$endpoint->setJsonRpcServerDispatcher($dispatcher); $requestHandler->setJsonRpcServerDispatcher($dispatcher); $exceptionHandler->setJsonRpcServerDispatcher($dispatcher);
Events dispatched
Basic request lifecycle
-
json_rpc_server_skd.on_request_received
/Acknowledge\OnRequestReceivedEvent
Dispatched when a request has been passed to the endpoint and successfully deserialized.
N.B. : Lonely cases where this event is not dispatched are when the request string is not a valid JSON-RPC request.
It include :
-
Parse error exception (malformed json string)
-
For simple request only, in case of Invalid request (not an object / missing required properties / ...).
⚠️ For batch request containing Invalid SubRequest, this event will still be dispatched
-
-
Either
-
json_rpc_server_skd.on_method_success
/Action\OnMethodSuccessEvent
Dispatched only in case JSON-RPC method has been successfully executed.
-
json_rpc_server_skd.on_method_failure
/Action\OnMethodFailureEvent
Dispatched only in case JSON-RPC method throw an exception during execution.
-
-
json_rpc_server_skd.on_response_sending
/Acknowledge\OnResponseSendingEvent
Dispatched when a response has been successfully serialized by the endpoint and will be returned.
Additional events
Batch request
-
json_rpc_server_skd.on_batch_sub_request_processing
/Acknowledge\OnBatchSubRequestProcessingEvent
Dispatched before that a sub request will be processed.
-
json_rpc_server_skd.on_batch_sub_request_processed
/Acknowledge\OnBatchSubRequestProcessedEvent
Dispatched after that a sub request has been processed (regardless of the success or failure of the sub request method execution).
Exception
json_rpc_server_skd.on_exception
/ Action\OnExceptionEvent
Dispatched when an exception occurred during sdk execution
Action vs Acknowledge events
Acknowledge
They have only an acknowledge purpose.
They are grouped under Yoanm\JsonRpcServer\Domain\Event\Acknowledge
namespace.
Action
They allow you to override stuffs.
They are grouped under Yoanm\JsonRpcServer\Domain\Event\Action
namespace.
Here, the list :
Action\OnMethodSuccessEvent
allow you to update/change the result of the method.Action\OnMethodFailureEvent
allow you to update/change the exception thrown by the method.Action\OnExceptionEvent
allow you to update/change the exception thrown.
Params validation example
You can use this JSON-RPC params symfony validator as example
To validate params for a given method, do the following :
use Yoanm\JsonRpcServer\Domain\JsonRpcMethodInterface; use Yoanm\JsonRpcServer\Domain\JsonRpcMethodParamsValidatorInterface; use Yoanm\JsonRpcServer\Domain\Model\JsonRpcRequest; $validator = new class implements JsonRpcMethodParamsValidatorInterface { public function validate(JsonRpcRequest $jsonRpcRequest, JsonRpcMethodInterface $method) : array { if (!(/** Skip unexpected method */)) { return []; } // Create your violations based on what you want $paramList = $jsonRpcRequest->getParamList(); $violation = "???"; return [$violation]; } }; $requestHandler->setMethodParamsValidator($validator);