Travailler avec JSON RPC dans Symfony 4


Bonjour à tous, aujourd'hui, nous allons parler de la façon de se faire des amis Symfony 4, JSON RPC et OpenAPI 3.


Cet article n'est pas destiné aux débutants, vous devez déjà comprendre comment travailler avec Symfony, Depedency Injection et d'autres choses "effrayantes".


Aujourd'hui, regardons une implémentation spécifique de JSON RPC.


Implémentations


Il existe de nombreuses implémentations JSON RPC pour Symfony, en particulier:



Nous parlerons de ce dernier dans cet article. Cette bibliothèque présente plusieurs avantages qui ont déterminé mon choix.


Il a été développé sans se lier à aucun framework ( yoanm / php-jsonrpc-server-sdk ), il existe un bundle pour Symfony, il a plusieurs packages supplémentaires qui vous permettent d'ajouter une vérification des entrées, une documentation automatique, des événements et des interfaces pour pouvoir compléter le travail sans redéfinition.


L'installation


Pour commencer, installez symfony / skeleton.


$ composer create-project symfony/skeleton jsonrpc 

Accédez au dossier du projet.


 $ cd jsonrpc 

Et installez la bibliothèque nécessaire.


 $ composer require yoanm/symfony-jsonrpc-http-server 

Personnalisable.


 // config/bundles.php return [ ... Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], Yoanm\SymfonyJsonRpcHttpServer\JsonRpcHttpServerBundle::class => ['all' => true], ... ]; 

 # config/routes.yaml json-rpc-endpoint: resource: '@JsonRpcHttpServerBundle/Resources/config/routing/endpoint.xml' 

 # config/packages/json_rpc.yaml json_rpc_http_server: ~ 

Ajoutez un service qui stockera toutes nos méthodes.


 // src/MappingCollector.php <?php namespace App; use Yoanm\JsonRpcServer\Domain\JsonRpcMethodAwareInterface; use Yoanm\JsonRpcServer\Domain\JsonRpcMethodInterface; class MappingCollector implements JsonRpcMethodAwareInterface { /** @var JsonRpcMethodInterface[] */ private $mappingList = []; public function addJsonRpcMethod(string $methodName, JsonRpcMethodInterface $method): void { $this->mappingList[$methodName] = $method; } /** * @return JsonRpcMethodInterface[] */ public function getMappingList() : array { return $this->mappingList; } } 

Et ajoutez le service à services.yaml.


 # config/services.yaml services: ... mapping_aware_service: class: App\MappingCollector tags: ['json_rpc_http_server.method_aware'] ... 

Implémentation de la méthode


Les méthodes RPC JSON sont ajoutées en tant que services standard dans le fichier services.yaml. Nous implémentons d'abord la méthode ping elle-même.


 // src/Method/PingMethod.php <?php namespace App\Method; use Yoanm\JsonRpcServer\Domain\JsonRpcMethodInterface; class PingMethod implements JsonRpcMethodInterface { public function apply(array $paramList = null) { return 'pong'; } } 

Et ajoutez en tant que service.


 # config/services.yaml services: ... App\Method\PingMethod: public: false tags: [{ method: 'ping', name: 'json_rpc_http_server.jsonrpc_method' }] ... 

Nous lançons le serveur Web intégré Symfony.


 $ symfony serve 

Nous essayons de faire un appel.


 $ curl 'http://127.0.0.1:8000/json-rpc' --data-binary '[{ "jsonrpc":"2.0","method":"ping","params":[],"id" : 1 }]' 

 [ { "jsonrpc": "2.0", "id": 1, "result": "pong" } ] 

Maintenant, nous implémentons la méthode qui reçoit les paramètres. Nous retournerons les données d'entrée comme réponse.


 // src/Method/ParamsMethod.php <?php namespace App\Method; use Yoanm\JsonRpcServer\Domain\JsonRpcMethodInterface; class ParamsMethod implements JsonRpcMethodInterface { public function apply(array $paramList = null) { return $paramList; } } 

 # config/services.yaml services: ... App\Method\ParamsMethod: public: false tags: [{ method: 'params', name: 'json_rpc_http_server.jsonrpc_method' }] ... 

Essayer d'appeler.


 $ curl 'http://127.0.0.1:8000/json-rpc' --data-binary '[{ "jsonrpc":"2.0","method":"params","params":{"name":"John","age":21},"id" : 1 }]' 

 [ { "jsonrpc": "2.0", "id": 1, "result": { "name": "John", "age": 21 } } ] 

Validation des entrées de méthode


Si une vérification automatique des données à l'entrée de la méthode est requise, alors dans ce cas il y a le package yoanm / symfony-jsonrpc-params-validator .


 $ composer require yoanm/symfony-jsonrpc-params-validator 

Connectez le bundle.


 // config/bundles.php return [ ... Yoanm\SymfonyJsonRpcParamsValidator\JsonRpcParamsValidatorBundle::class => ['all' => true], ... ]; 

Les méthodes qui doivent vérifier l'entrée doivent implémenter l' interface Yoanm \ JsonRpcParamsSymfonyValidator \ Domain \ MethodWithValidatedParamsInterface . Modifions un peu la classe ParamsMethod .


 // src/Method/ParamsMethod.php <?php namespace App\Method; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Choice; use Symfony\Component\Validator\Constraints\Collection; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\Optional; use Symfony\Component\Validator\Constraints\Positive; use Symfony\Component\Validator\Constraints\Required; use Yoanm\JsonRpcParamsSymfonyValidator\Domain\MethodWithValidatedParamsInterface; use Yoanm\JsonRpcServer\Domain\JsonRpcMethodInterface; class ParamsMethod implements JsonRpcMethodInterface, MethodWithValidatedParamsInterface { public function apply(array $paramList = null) { return $paramList; } public function getParamsConstraint() : Constraint { return new Collection(['fields' => [ 'name' => new Required([ new Length(['min' => 1, 'max' => 32]) ]), 'age' => new Required([ new Positive() ]), 'sex' => new Optional([ new Choice(['f', 'm']) ]), ]]); } } 

Maintenant, si nous exécutons la demande avec des paramètres vides ou avec des erreurs, nous recevrons les erreurs correspondantes en réponse.


 $ curl 'http://127.0.0.1:8000/json-rpc' --data-binary '[{"jsonrpc":"2.0","method":"params","params":[],"id" : 1 }]' 

 [ { "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "Invalid params", "data": { "violations": [ { "path": "[name]", "message": "This field is missing.", "code": "2fa2158c-2a7f-484b-98aa-975522539ff8" }, { "path": "[age]", "message": "This field is missing.", "code": "2fa2158c-2a7f-484b-98aa-975522539ff8" } ] } } } ] 

 $ curl 'http://127.0.0.1:8000/json-rpc' --data-binary '[{"jsonrpc":"2.0","method":"params","params":{"name":"John","age":-1},"id" : 1 }]' 

 [ { "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "Invalid params", "data": { "violations": [ { "path": "[age]", "message": "This value should be positive.", "code": "778b7ae0-84d3-481a-9dec-35fdb64b1d78" } ] } } } 

 $ curl 'http://127.0.0.1:8000/json-rpc' --data-binary '[{ "jsonrpc":"2.0","method":"params","params":{"name":"John","age":21,"sex":"u"},"id" : 1 }]' 

 [ { "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "Invalid params", "data": { "violations": [ { "path": "[sex]", "message": "The value you selected is not a valid choice.", "code": "8e179f1b-97aa-4560-a02f-2a8b42e49df7" } ] } } } ] 

Documentation automatique


Installez un package supplémentaire.


 composer require yoanm/symfony-jsonrpc-http-server-doc 

Nous configurons le bundle.


 // config/bundles.php return [ ... Yoanm\SymfonyJsonRpcHttpServerDoc\JsonRpcHttpServerDocBundle::class => ['all' => true], ... ]; 

 # config/routes.yaml ... json-rpc-endpoint-doc: resource: '@JsonRpcHttpServerDocBundle/Resources/config/routing/endpoint.xml' 

 # config/packages/json_rpc.yaml ... json_rpc_http_server_doc: ~ 

Vous pouvez maintenant obtenir la documentation au format JSON.


 $ curl 'http://127.0.0.1:8000/doc' 

La réponse
 { "methods": [ { "identifier": "Params", "name": "params" }, { "identifier": "Ping", "name": "ping" } ], "errors": [ { "id": "ParseError-32700", "title": "Parse error", "type": "object", "properties": { "code": -32700 } }, { "id": "InvalidRequest-32600", "title": "Invalid request", "type": "object", "properties": { "code": -32600 } }, { "id": "MethodNotFound-32601", "title": "Method not found", "type": "object", "properties": { "code": -32601 } }, { "id": "ParamsValidationsError-32602", "title": "Params validations error", "type": "object", "properties": { "code": -32602, "data": { "type": "object", "nullable": true, "required": true, "siblings": { "violations": { "type": "array", "nullable": true, "required": false } } } } }, { "id": "InternalError-32603", "title": "Internal error", "type": "object", "properties": { "code": -32603, "data": { "type": "object", "nullable": true, "required": false, "siblings": { "previous": { "description": "Previous error message", "type": "string", "nullable": true, "required": false } } } } } ], "http": { "host": "127.0.0.1:8000" } } 

Mais comment ça? Et où est la description des paramètres d'entrée? Pour ce faire, mettez un autre bundle yoanm / symfony-jsonrpc-params-sf-contraintes-doc .


 $ composer require yoanm/symfony-jsonrpc-params-sf-constraints-doc 

 // config/bundles.php return [ ... Yoanm\SymfonyJsonRpcParamsSfConstraintsDoc\JsonRpcParamsSfConstraintsDocBundle::class => ['all' => true], ... ]; 

Maintenant, si nous faisons une demande, nous aurons déjà des méthodes JSON avec des paramètres.


 $ curl 'http://127.0.0.1:8000/doc' 

La réponse
 { "methods": [ { "identifier": "Params", "name": "params", "params": { "type": "object", "nullable": false, "required": true, "siblings": { "name": { "type": "string", "nullable": true, "required": true, "minLength": 1, "maxLength": 32 }, "age": { "type": "string", "nullable": true, "required": true }, "sex": { "type": "string", "nullable": true, "required": false, "allowedValues": [ "f", "m" ] } } } }, { "identifier": "Ping", "name": "ping" } ], "errors": [ { "id": "ParseError-32700", "title": "Parse error", "type": "object", "properties": { "code": -32700 } }, { "id": "InvalidRequest-32600", "title": "Invalid request", "type": "object", "properties": { "code": -32600 } }, { "id": "MethodNotFound-32601", "title": "Method not found", "type": "object", "properties": { "code": -32601 } }, { "id": "ParamsValidationsError-32602", "title": "Params validations error", "type": "object", "properties": { "code": -32602, "data": { "type": "object", "nullable": true, "required": true, "siblings": { "violations": { "type": "array", "nullable": true, "required": false, "item_validation": { "type": "object", "nullable": true, "required": true, "siblings": { "path": { "type": "string", "nullable": true, "required": true, "example": "[key]" }, "message": { "type": "string", "nullable": true, "required": true }, "code": { "type": "string", "nullable": true, "required": false } } } } } } } }, { "id": "InternalError-32603", "title": "Internal error", "type": "object", "properties": { "code": -32603, "data": { "type": "object", "nullable": true, "required": false, "siblings": { "previous": { "description": "Previous error message", "type": "string", "nullable": true, "required": false } } } } } ], "http": { "host": "127.0.0.1:8000" } } 

Openapi 3


Pour que la documentation JSON soit compatible avec la norme OpenAPI 3, vous devez installer yoanm / symfony-jsonrpc-http-server-openapi-doc .


 $ composer require yoanm/symfony-jsonrpc-http-server-openapi-doc 

Personnalisable.


 // config/bundles.php return [ ... Yoanm\SymfonyJsonRpcHttpServerOpenAPIDoc\JsonRpcHttpServerOpenAPIDocBundle::class => ['all' => true], ... ]; 

Après avoir fait une nouvelle demande, nous recevrons la documentation JSON au format OpenApi 3.


 $ curl 'http://127.0.0.1:8000/doc/openapi.json' 

La réponse
 { "openapi": "3.0.0", "servers": [ { "url": "http:\/\/127.0.0.1:8000" } ], "paths": { "\/Params\/..\/json-rpc": { "post": { "summary": "\"params\" json-rpc method", "operationId": "Params", "requestBody": { "required": true, "content": { "application\/json": { "schema": { "allOf": [ { "type": "object", "required": [ "jsonrpc", "method" ], "properties": { "id": { "example": "req_id", "oneOf": [ { "type": "string" }, { "type": "number" } ] }, "jsonrpc": { "type": "string", "example": "2.0" }, "method": { "type": "string" }, "params": { "title": "Method parameters" } } }, { "type": "object", "required": [ "params" ], "properties": { "params": { "$ref": "#\/components\/schemas\/Method-Params-RequestParams" } } }, { "type": "object", "properties": { "method": { "example": "params" } } } ] } } } }, "responses": { "200": { "description": "JSON-RPC response", "content": { "application\/json": { "schema": { "allOf": [ { "type": "object", "required": [ "jsonrpc" ], "properties": { "id": { "example": "req_id", "oneOf": [ { "type": "string" }, { "type": "number" } ] }, "jsonrpc": { "type": "string", "example": "2.0" }, "result": { "title": "Result" }, "error": { "title": "Error" } } }, { "type": "object", "properties": { "result": { "description": "Method result" } } }, { "type": "object", "properties": { "error": { "oneOf": [ { "$ref": "#\/components\/schemas\/ServerError-ParseError-32700" }, { "$ref": "#\/components\/schemas\/ServerError-InvalidRequest-32600" }, { "$ref": "#\/components\/schemas\/ServerError-MethodNotFound-32601" }, { "$ref": "#\/components\/schemas\/ServerError-ParamsValidationsError-32602" }, { "$ref": "#\/components\/schemas\/ServerError-InternalError-32603" } ] } } } ] } } } } } } }, "\/Ping\/..\/json-rpc": { "post": { "summary": "\"ping\" json-rpc method", "operationId": "Ping", "requestBody": { "required": true, "content": { "application\/json": { "schema": { "allOf": [ { "type": "object", "required": [ "jsonrpc", "method" ], "properties": { "id": { "example": "req_id", "oneOf": [ { "type": "string" }, { "type": "number" } ] }, "jsonrpc": { "type": "string", "example": "2.0" }, "method": { "type": "string" }, "params": { "title": "Method parameters" } } }, { "type": "object", "properties": { "method": { "example": "ping" } } } ] } } } }, "responses": { "200": { "description": "JSON-RPC response", "content": { "application\/json": { "schema": { "allOf": [ { "type": "object", "required": [ "jsonrpc" ], "properties": { "id": { "example": "req_id", "oneOf": [ { "type": "string" }, { "type": "number" } ] }, "jsonrpc": { "type": "string", "example": "2.0" }, "result": { "title": "Result" }, "error": { "title": "Error" } } }, { "type": "object", "properties": { "result": { "description": "Method result" } } }, { "type": "object", "properties": { "error": { "oneOf": [ { "$ref": "#\/components\/schemas\/ServerError-ParseError-32700" }, { "$ref": "#\/components\/schemas\/ServerError-InvalidRequest-32600" }, { "$ref": "#\/components\/schemas\/ServerError-MethodNotFound-32601" }, { "$ref": "#\/components\/schemas\/ServerError-ParamsValidationsError-32602" }, { "$ref": "#\/components\/schemas\/ServerError-InternalError-32603" } ] } } } ] } } } } } } } }, "components": { "schemas": { "Method-Params-RequestParams": { "type": "object", "nullable": false, "required": [ "name", "age" ], "properties": { "name": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 32 }, "age": { "type": "string", "nullable": true }, "sex": { "type": "string", "nullable": true, "enum": [ "f", "m" ] } } }, "ServerError-ParseError-32700": { "title": "Parse error", "allOf": [ { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "number" }, "message": { "type": "string" } } }, { "type": "object", "required": [ "code" ], "properties": { "code": { "example": -32700 } } } ] }, "ServerError-InvalidRequest-32600": { "title": "Invalid request", "allOf": [ { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "number" }, "message": { "type": "string" } } }, { "type": "object", "required": [ "code" ], "properties": { "code": { "example": -32600 } } } ] }, "ServerError-MethodNotFound-32601": { "title": "Method not found", "allOf": [ { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "number" }, "message": { "type": "string" } } }, { "type": "object", "required": [ "code" ], "properties": { "code": { "example": -32601 } } } ] }, "ServerError-ParamsValidationsError-32602": { "title": "Params validations error", "allOf": [ { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "number" }, "message": { "type": "string" } } }, { "type": "object", "required": [ "code", "data" ], "properties": { "code": { "example": -32602 }, "data": { "type": "object", "nullable": true, "properties": { "violations": { "type": "array", "nullable": true, "items": { "type": "object", "nullable": true, "required": [ "path", "message" ], "properties": { "path": { "type": "string", "nullable": true, "example": "[key]" }, "message": { "type": "string", "nullable": true }, "code": { "type": "string", "nullable": true } } } } } } } } ] }, "ServerError-InternalError-32603": { "title": "Internal error", "allOf": [ { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "number" }, "message": { "type": "string" } } }, { "type": "object", "required": [ "code" ], "properties": { "code": { "example": -32603 }, "data": { "type": "object", "nullable": true, "properties": { "previous": { "description": "Previous error message", "type": "string", "nullable": true } } } } } ] } } } } 

Documentation de réponse de méthode


Il n'y a pas de fonctionnalité régulière (par exemple, en implémentant une interface) qui vous permet d'ajouter des réponses de méthode à la documentation. Mais il est possible, en vous abonnant à des événements, d'ajouter vous-même les informations nécessaires.


Ajoutez un écouteur.


 # config/services.yaml services: ... App\Listener\MethodDocListener: tags: - name: 'kernel.event_listener' event: 'json_rpc_http_server_doc.method_doc_created' method: 'enhanceMethodDoc' - name: 'kernel.event_listener' event: 'json_rpc_http_server_openapi_doc.array_created' method: 'enhanceDoc' ... 

 // src/Listener/MethodDocListener.php <?php namespace App\Listener; use App\Domain\JsonRpcMethodWithDocInterface; use Yoanm\JsonRpcServerDoc\Domain\Model\ErrorDoc; use Yoanm\SymfonyJsonRpcHttpServerDoc\Event\MethodDocCreatedEvent; use Yoanm\SymfonyJsonRpcHttpServerOpenAPIDoc\Event\OpenAPIDocCreatedEvent; class MethodDocListener { public function enhanceMethodDoc(MethodDocCreatedEvent $event) : void { $method = $event->getMethod(); if ($method instanceof JsonRpcMethodWithDocInterface) { $doc = $event->getDoc(); $doc->setResultDoc($method->getDocResponse()); foreach ($method->getDocErrors() as $error) { if ($error instanceof ErrorDoc) { $doc->addCustomError($error); } } $doc->setDescription($method->getDocDescription()); $doc->addTag($method->getDocTag()); } } public function enhanceDoc(OpenAPIDocCreatedEvent $event) { $doc = $event->getOpenAPIDoc(); $doc['info'] = [ 'title' => 'Main title', 'version' => '1.0.0', 'description' => 'Main description' ]; $event->setOpenAPIDoc($doc); } } 

Aussi, afin de ne pas décrire la documentation des méthodes directement dans l'écouteur, nous allons créer une interface que les méthodes elles-mêmes devront implémenter.


 // src/Domain/JsonRpcMethodWithDocInterface.php <?php namespace App\Domain; use Yoanm\JsonRpcServerDoc\Domain\Model\ErrorDoc; use Yoanm\JsonRpcServerDoc\Domain\Model\Type\TypeDoc; interface JsonRpcMethodWithDocInterface { /** * @return TypeDoc */ public function getDocResponse(): TypeDoc; /** * @return ErrorDoc[] */ public function getDocErrors(): array; /** * @return string */ public function getDocDescription(): string; /** * @return string */ public function getDocTag(): string; } 

Ajoutez maintenant une nouvelle méthode qui contiendra les informations nécessaires.


 // src/Method/UserMethod.php <?php namespace App\Method; use App\Domain\JsonRpcMethodWithDocInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Choice; use Symfony\Component\Validator\Constraints\Collection; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\Optional; use Symfony\Component\Validator\Constraints\Positive; use Symfony\Component\Validator\Constraints\Required; use Yoanm\JsonRpcParamsSymfonyValidator\Domain\MethodWithValidatedParamsInterface; use Yoanm\JsonRpcServer\Domain\JsonRpcMethodInterface; use Yoanm\JsonRpcServerDoc\Domain\Model\ErrorDoc; use Yoanm\JsonRpcServerDoc\Domain\Model\Type\ArrayDoc; use Yoanm\JsonRpcServerDoc\Domain\Model\Type\NumberDoc; use Yoanm\JsonRpcServerDoc\Domain\Model\Type\ObjectDoc; use Yoanm\JsonRpcServerDoc\Domain\Model\Type\StringDoc; use Yoanm\JsonRpcServerDoc\Domain\Model\Type\TypeDoc; class UserMethod implements JsonRpcMethodInterface, MethodWithValidatedParamsInterface, JsonRpcMethodWithDocInterface { public function apply(array $paramList = null) { return [ 'name' => $paramList['name'], 'age' => $paramList['age'], 'sex' => $paramList['sex'] ?? null, ]; } public function getParamsConstraint() : Constraint { return new Collection(['fields' => [ 'name' => new Required([ new Length(['min' => 1, 'max' => 32]) ]), 'age' => new Required([ new Positive() ]), 'sex' => new Optional([ new Choice(['f', 'm']) ]), ]]); } public function getDocDescription(): string { return 'User method'; } public function getDocTag(): string { return 'main'; } public function getDocErrors(): array { return [new ErrorDoc('Error 1', 1)]; } public function getDocResponse(): TypeDoc { $response = new ObjectDoc(); $response->setNullable(false); $response->addSibling((new StringDoc()) ->setNullable(false) ->setDescription('Name of user') ->setName('name') ); $response->addSibling((new NumberDoc()) ->setNullable(false) ->setDescription('Age of user') ->setName('age') ); $response->addSibling((new StringDoc()) ->setNullable(true) ->setDescription('Sex of user') ->setName('sex') ); return $response; } } 

N'oubliez pas d'enregistrer un nouveau service.


 services: ... App\Method\UserMethod: public: false tags: [{ method: 'user', name: 'json_rpc_http_server.jsonrpc_method' }] ... 

Maintenant, en faisant une nouvelle demande à /doc/openapi.json , nous obtenons de nouvelles données.


 curl 'http://127.0.0.1:8000/doc/openapi.json' 

La réponse
 { "openapi": "3.0.0", "servers": [ { "url": "http:\/\/127.0.0.1:8000" } ], "paths": { ... "\/User\/..\/json-rpc": { "post": { "summary": "\"user\" json-rpc method", "description": "User method", "tags": [ "main" ], ... "responses": { "200": { "description": "JSON-RPC response", "content": { "application\/json": { "schema": { "allOf": [ ... { "type": "object", "properties": { "result": { "$ref": "#\/components\/schemas\/Method-User-Result" } } }, { "type": "object", "properties": { "error": { "oneOf": [ { "$ref": "#\/components\/schemas\/Error-Error11" }, ... ] } } } ] } } } } } } } }, "components": { "schemas": { ... "Method-User-Result": { "type": "object", "nullable": false, "properties": { "name": { "description": "Name of user", "type": "string", "nullable": false }, "age": { "description": "Age of user", "type": "number", "nullable": false }, "sex": { "description": "Sex of user", "type": "string", "nullable": true } } }, "Error-Error11": { "title": "Error 1", "allOf": [ { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "number" }, "message": { "type": "string" } } }, { "type": "object", "required": [ "code" ], "properties": { "code": { "example": 1 } } } ] }, ... } }, "info": { "title": "Main title", "version": "1.0.0", "description": "Main description" } } 

Visualisation de la documentation JSON


JSON est cool, mais les gens veulent généralement voir un résultat plus humain. Le fichier /doc/openapi.json peut être attribué à des services de visualisation externes, tels que Swagger Editor .



Si vous le souhaitez, vous pouvez installer Swagger UI dans notre projet. Nous utiliserons le paquet harmbandstra / swagger-ui-bundle .


Pour la publication correcte des ressources, nous ajoutons ce qui suit avec composer.json.


  "scripts": { "auto-scripts": { "cache:clear": "symfony-cmd", "assets:install %PUBLIC_DIR%": "symfony-cmd" }, "post-install-cmd": [ "HarmBandstra\\SwaggerUiBundle\\Composer\\ScriptHandler::linkAssets", "@auto-scripts" ], "post-update-cmd": [ "HarmBandstra\\SwaggerUiBundle\\Composer\\ScriptHandler::linkAssets", "@auto-scripts" ] }, 

Après avoir mis le paquet.


 $ composer require harmbandstra/swagger-ui-bundle 

Connectez le bundle.


 // config/bundles.php <?php return [ // ... HarmBandstra\SwaggerUiBundle\HBSwaggerUiBundle::class => ['dev' => true] ]; 

 # config/routes.yaml _swagger-ui: resource: '@HBSwaggerUiBundle/Resources/config/routing.yml' prefix: /docs 

 # config/packages/hb_swagger_ui.yaml hb_swagger_ui: directory: "http://127.0.0.1:8000" files: - "/doc/openapi.json" 

Maintenant, en suivant le lien http://127.0.0.1:8000/docs/, nous obtenons la documentation sous une belle forme.



Résumé


À la suite de toutes les manipulations, nous avons obtenu un JSON RPC fonctionnel basé sur Symfony 4 et une documentation automatique d'OpenAPI avec visualisation à l'aide de Swagger UI.


Merci à tous.

Source: https://habr.com/ru/post/fr457750/


All Articles