From ce3360ba5a1e6bf4f9a90c767c7a329b740be7bc Mon Sep 17 00:00:00 2001 From: Paul Klimov Date: Fri, 28 Apr 2023 17:53:24 +0300 Subject: [PATCH 1/4] add configurable debug mode --- composer.json | 2 +- src/DependencyInjection/Configuration.php | 22 +++++++++++++++++++ .../JsonRpcHttpServerExtension.php | 19 ++++++++++++---- src/Resources/config/sdk.services.app.yaml | 12 ++++++++-- 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index cf17ee9..d604774 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "symfony/event-dispatcher-contracts": "^1.0 || ^2.0 || ^3.0", "symfony/http-foundation": "^4.4 || ^5.4 || ^6.0", "symfony/http-kernel": "^4.4 || ^5.4 || ^6.0", - "yoanm/jsonrpc-server-sdk": "^3.0" + "yoanm/jsonrpc-server-sdk": "^3.3" }, "require-dev": { "behat/behat": "^3.9.0", diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 0f7e9e2..f756686 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -22,6 +22,28 @@ public function getConfigTreeBuilder() ->treatNullLike(self::DEFAULT_ENDPOINT) ->defaultValue(self::DEFAULT_ENDPOINT) ->end() + ->arrayNode('debug') + ->addDefaultsIfNotSet() + ->children() + ->booleanNode('enabled') + ->info('Whether to render debug information on error or not (should NOT be enabled on prod)') + ->defaultFalse() + ->end() + ->integerNode('max_trace_size') + ->info('Max debug trace size') + ->min(0) + ->defaultValue(10) + ->end() + ->booleanNode('show_trace_arguments') + ->info('Whether to render debug stack trace arguments or not') + ->defaultValue(true) + ->end() + ->booleanNode('simplify_trace_arguments') + ->info('Whether to simplify representation of debug stack trace arguments or not') + ->defaultValue(true) + ->end() + ->end() + ->end() ->end() ; diff --git a/src/DependencyInjection/JsonRpcHttpServerExtension.php b/src/DependencyInjection/JsonRpcHttpServerExtension.php index 9922002..c6e9198 100644 --- a/src/DependencyInjection/JsonRpcHttpServerExtension.php +++ b/src/DependencyInjection/JsonRpcHttpServerExtension.php @@ -66,7 +66,8 @@ public function process(ContainerBuilder $container) { $this->bindJsonRpcServerDispatcher($container); $this->bindValidatorIfDefined($container); - $this->binJsonRpcMethods($container); + $this->bindJsonRpcMethods($container); + $this->bindDebug($container); } /** @@ -102,9 +103,11 @@ private function compileAndProcessConfigurations(array $configs, ContainerBuilde $configuration = new Configuration(); $config = (new Processor())->processConfiguration($configuration, $configs); - $httpEndpointPath = $config['endpoint']; + $container->setParameter(self::ENDPOINT_PATH_CONTAINER_PARAM_ID, $config['endpoint']); - $container->setParameter(self::ENDPOINT_PATH_CONTAINER_PARAM_ID, $httpEndpointPath); + foreach ($config['debug'] as $name => $value) { + $container->setParameter(self::EXTENSION_IDENTIFIER.'.debug.'.$name, $value); + } } /** @@ -149,7 +152,7 @@ private function bindValidatorIfDefined(ContainerBuilder $container) : void /** * @param ContainerBuilder $container */ - private function binJsonRpcMethods(ContainerBuilder $container) : void + private function bindJsonRpcMethods(ContainerBuilder $container) : void { $mappingAwareServiceDefinitionList = $this->findAndValidateMappingAwareDefinitionList($container); @@ -223,4 +226,12 @@ private function checkMethodAwareServiceIdList( )); } } + + private function bindDebug(ContainerBuilder $container) : void + { + if ($container->getParameter('json_rpc_http_server.debug.enabled')) { + $container->getDefinition('json_rpc_server_sdk.app.serialization.jsonrpc_response_normalizer') + ->addArgument(new Reference('json_rpc_server_sdk.app.serialization.jsonrpc_response_error_normalizer')); + } + } } diff --git a/src/Resources/config/sdk.services.app.yaml b/src/Resources/config/sdk.services.app.yaml index f49b866..09c0f1f 100644 --- a/src/Resources/config/sdk.services.app.yaml +++ b/src/Resources/config/sdk.services.app.yaml @@ -1,5 +1,5 @@ services: - #Serialization + # Serialization json_rpc_server_sdk.app.serialization.jsonrpc_request_denormalizer: class: Yoanm\JsonRpcServer\App\Serialization\JsonRpcRequestDenormalizer @@ -22,7 +22,7 @@ services: - '@json_rpc_server_sdk.app.serialization.jsonrpc_call_dernormalizer' - '@json_rpc_server_sdk.app.serialization.jsonrpc_call_response_normalizer' - #Handlers + # Handlers json_rpc_server_sdk.app.handler.jsonrpc_request: class: Yoanm\JsonRpcServer\App\Handler\JsonRpcRequestHandler arguments: @@ -39,3 +39,11 @@ services: # Creator json_rpc_server_sdk.app.creator.response: class: Yoanm\JsonRpcServer\App\Creator\ResponseCreator + + # Debug + json_rpc_server_sdk.app.serialization.jsonrpc_response_error_normalizer: + class: Yoanm\JsonRpcServer\App\Serialization\JsonRpcResponseErrorNormalizer + arguments: + - '%json_rpc_http_server.debug.max_trace_size%' + - '%json_rpc_http_server.debug.show_trace_arguments%' + - '%json_rpc_http_server.debug.simplify_trace_arguments%' From 500feaf14c90640cc2e5a678bf834502482e0d8a Mon Sep 17 00:00:00 2001 From: Paul Klimov Date: Fri, 28 Apr 2023 18:03:28 +0300 Subject: [PATCH 2/4] add docs about debug mode --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 6c61d13..e969118 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,36 @@ mapping_aware_service: tags: ['json_rpc_http_server.method_aware'] ``` +## Debug mode + +You can setup 'debug' mode for the JSON-RPC server, which allows display of verbose error information within the response JSON body. +This information contains actual exception class name, code, message and stack trace. + +> Note: you should never enable 'debug' mode in 'production' environment, since it will expose vital internal information to the API consumer. + +Configuration example: + +```yaml +# file 'config/packages/json_rpc.yaml' +json_rpc_http_server: + endpoint: '/json-rpc' + debug: + enabled: false + max_trace_size: 10 + show_trace_arguments: true + simplify_trace_arguments: true + +when@dev: + json_rpc_http_server: + debug: + enabled: true + +when@test: + json_rpc_http_server: + debug: + enabled: true +``` + ## Contributing See [contributing note](./CONTRIBUTING.md) From 76abf415faa0fd3b2ab112f5322b607248ccc865 Mon Sep 17 00:00:00 2001 From: Paul Klimov Date: Fri, 28 Apr 2023 18:10:43 +0300 Subject: [PATCH 3/4] fix constant usage --- .../JsonRpcHttpServerExtension.php | 12 ++++++------ src/JsonRpcHttpServerBundle.php | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/DependencyInjection/JsonRpcHttpServerExtension.php b/src/DependencyInjection/JsonRpcHttpServerExtension.php index c6e9198..f6b90bd 100644 --- a/src/DependencyInjection/JsonRpcHttpServerExtension.php +++ b/src/DependencyInjection/JsonRpcHttpServerExtension.php @@ -14,7 +14,7 @@ use Yoanm\JsonRpcServer\Domain\JsonRpcMethodAwareInterface; /** - * Class JsonRpcHttpServerExtension + * @see \Yoanm\SymfonyJsonRpcHttpServer\DependencyInjection\Configuration */ class JsonRpcHttpServerExtension implements ExtensionInterface, CompilerPassInterface { @@ -115,7 +115,7 @@ private function compileAndProcessConfigurations(array $configs, ContainerBuilde */ private function bindJsonRpcServerDispatcher(ContainerBuilder $container) : void { - $dispatcherRef = new Reference('json_rpc_http_server.dispatcher.server'); + $dispatcherRef = new Reference(self::EXTENSION_IDENTIFIER.'.dispatcher.server'); $dispatcherAwareServiceList = $container->findTaggedServiceIds(self::JSONRPC_SERVER_DISPATCHER_AWARE_TAG); foreach ($dispatcherAwareServiceList as $serviceId => $tagAttributeList) { $definition = $container->getDefinition($serviceId); @@ -169,7 +169,7 @@ private function bindJsonRpcMethods(ContainerBuilder $container) : void // Service locator for method resolver // => first argument is an array of wanted service with keys as alias for internal use - $container->getDefinition('json_rpc_http_server.service_locator.method_resolver') + $container->getDefinition(self::EXTENSION_IDENTIFIER.'.service_locator.method_resolver') ->setArgument(0, $methodMappingList); } @@ -229,9 +229,9 @@ private function checkMethodAwareServiceIdList( private function bindDebug(ContainerBuilder $container) : void { - if ($container->getParameter('json_rpc_http_server.debug.enabled')) { - $container->getDefinition('json_rpc_server_sdk.app.serialization.jsonrpc_response_normalizer') - ->addArgument(new Reference('json_rpc_server_sdk.app.serialization.jsonrpc_response_error_normalizer')); + if ($container->getParameter(self::EXTENSION_IDENTIFIER.'.debug.enabled')) { + $container->getDefinition(self::EXTENSION_IDENTIFIER.'.app.serialization.jsonrpc_response_normalizer') + ->addArgument(new Reference(self::EXTENSION_IDENTIFIER.'.app.serialization.jsonrpc_response_error_normalizer')); } } } diff --git a/src/JsonRpcHttpServerBundle.php b/src/JsonRpcHttpServerBundle.php index 2a25db6..20c6bae 100644 --- a/src/JsonRpcHttpServerBundle.php +++ b/src/JsonRpcHttpServerBundle.php @@ -4,7 +4,7 @@ use Symfony\Component\HttpKernel\Bundle\Bundle; /** - * Class JsonRpcHttpServerBundle + * @see \Yoanm\SymfonyJsonRpcHttpServer\DependencyInjection\JsonRpcHttpServerExtension */ class JsonRpcHttpServerBundle extends Bundle { From fc5c7772a8869605b1fd232a9d7ccecb9de53563 Mon Sep 17 00:00:00 2001 From: Yoanm Date: Sun, 30 Apr 2023 16:16:42 +0200 Subject: [PATCH 4/4] Fix + UTs --- src/DependencyInjection/Configuration.php | 4 +++- .../JsonRpcHttpServerExtension.php | 4 ++-- .../DependencyInjection/ConfigFilesTest.php | 6 ++++++ .../JsonRpcHttpServerExtensionTest.php | 18 ++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index f756686..5bf6c1a 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -26,7 +26,9 @@ public function getConfigTreeBuilder() ->addDefaultsIfNotSet() ->children() ->booleanNode('enabled') - ->info('Whether to render debug information on error or not (should NOT be enabled on prod)') + ->info( + 'Whether to render debug information on error or not (should NOT be enabled on prod)' + ) ->defaultFalse() ->end() ->integerNode('max_trace_size') diff --git a/src/DependencyInjection/JsonRpcHttpServerExtension.php b/src/DependencyInjection/JsonRpcHttpServerExtension.php index f6b90bd..d793025 100644 --- a/src/DependencyInjection/JsonRpcHttpServerExtension.php +++ b/src/DependencyInjection/JsonRpcHttpServerExtension.php @@ -230,8 +230,8 @@ private function checkMethodAwareServiceIdList( private function bindDebug(ContainerBuilder $container) : void { if ($container->getParameter(self::EXTENSION_IDENTIFIER.'.debug.enabled')) { - $container->getDefinition(self::EXTENSION_IDENTIFIER.'.app.serialization.jsonrpc_response_normalizer') - ->addArgument(new Reference(self::EXTENSION_IDENTIFIER.'.app.serialization.jsonrpc_response_error_normalizer')); + $container->getDefinition('json_rpc_server_sdk.app.serialization.jsonrpc_response_normalizer') + ->addArgument(new Reference('json_rpc_server_sdk.app.serialization.jsonrpc_response_error_normalizer')); } } } diff --git a/tests/Functional/DependencyInjection/ConfigFilesTest.php b/tests/Functional/DependencyInjection/ConfigFilesTest.php index 0f982f9..2b8e846 100644 --- a/tests/Functional/DependencyInjection/ConfigFilesTest.php +++ b/tests/Functional/DependencyInjection/ConfigFilesTest.php @@ -11,6 +11,7 @@ use Yoanm\JsonRpcServer\App\Serialization\JsonRpcCallSerializer; use Yoanm\JsonRpcServer\App\Serialization\JsonRpcRequestDenormalizer; use Yoanm\JsonRpcServer\App\Serialization\JsonRpcResponseNormalizer; +use Yoanm\JsonRpcServer\App\Serialization\JsonRpcResponseErrorNormalizer; use Yoanm\JsonRpcServer\Infra\Endpoint\JsonRpcEndpoint; use Yoanm\SymfonyJsonRpcHttpServer\DependencyInjection\JsonRpcHttpServerExtension; use Yoanm\SymfonyJsonRpcHttpServer\Dispatcher\SymfonyJsonRpcServerDispatcher; @@ -100,6 +101,11 @@ public function provideSDKAppServiceIdAndClass() 'serviceClassName' => ResponseCreator::class, 'public' => false, ], + 'SDK - App - Response error normalizer' => [ + 'serviceId' => 'json_rpc_server_sdk.app.serialization.jsonrpc_response_error_normalizer', + 'serviceClassName' => JsonRpcResponseErrorNormalizer::class, + 'public' => false, + ], ]; } diff --git a/tests/Functional/DependencyInjection/JsonRpcHttpServerExtensionTest.php b/tests/Functional/DependencyInjection/JsonRpcHttpServerExtensionTest.php index 2aac4c7..7ab86df 100644 --- a/tests/Functional/DependencyInjection/JsonRpcHttpServerExtensionTest.php +++ b/tests/Functional/DependencyInjection/JsonRpcHttpServerExtensionTest.php @@ -185,4 +185,22 @@ public function testShouldThowAnExceptionIfMethodAwareServiceDoesNotImplementRig $this->loadContainer(); } + + public function testShouldAddDebugResponseErrorNormalizerIfDebugModeEnabled() + { + $this->loadContainer([ + 'debug' => [ + 'enabled' => true, + ] + ]); + + // Assert response normalizer has responseErrorNormalizer as first argument + $this->assertContainerBuilderHasServiceDefinitionWithArgument( + 'json_rpc_server_sdk.app.serialization.jsonrpc_response_normalizer', + 0, + new Reference('json_rpc_server_sdk.app.serialization.jsonrpc_response_error_normalizer'), + ); + + $this->assertEndpointIsUsable(); + } }