insidestyles/json-rpc-bundle

A simple and fast way to create json rpc server api as microservice. Json Rpc 2.0 Bundle

Installs: 497

Dependents: 0

Suggesters: 0

Security: 0

Stars: 2

Watchers: 2

Forks: 0

Open Issues: 0

Type:symfony-bundle

v3.0.0 2023-02-05 12:57 UTC

This package is auto-updated.

Last update: 2024-04-05 15:29:32 UTC


README

Symfony Json Rpc Bundle Fast way to create json rpc microservice, using symfony messenger and laminas json server

  • Json Rpc 2.0
  • Batch Support

Requirements

    "php": ">=8.0",
    "ext-json": "*",
    "symfony/framework-bundle": "^5.3" || ^6.0,
    "laminas/laminas-json-server": "^3.1"

Installation

This package is installable and autoloadable via Composer

composer require insidestyles/json-rpc-bundle

Add package config: json_rpc_api.yaml

json_rpc_api:
    handlers:
        main:
            path: /api
            host: ~
            serializer: ~
            context: ~
            logger: ~
            error_handler: ~

Add Bundle to App

    Insidestyles\JsonRpcBundle\JsonRpcBundle::class => ['all' => true],

Add route config: json_rpc_api_routing.yaml

_json_rpc_api:
  resource: .
  type: json_rpc_api

Usage

  • Add Example HelloWorldApi

Update api interface with JsonRpcApi Annotation

@JsonRpcApi(namespace = "main")

<?php
    /**
     * @JsonRpcApi(namespace = "main")
     *
     * @author Fuong <insidestyles@gmail.com>
     */
    interface HelloWordJsonRpcApiInterface extends JsonRpcApiInterface
    {
        public function helloWorld(string $name);
    }
    
  • HelloWorld Api with Symfony Messenger:

Add requirement:

composer require symfony/messenger

Config Symfony Messenger https://symfony.com/doc/current/messenger.html

services:

    hello_world_api:
        class: Insidestyles\JsonRpcBundle\Api\MessageBus\HelloWorldApi
        arguments:
            - "@messenger.bus.default"
        tags:
            - {name: json_rpc_api, handler: main}

    hello_world_api_handler:
        class: Insidestyles\JsonRpcBundle\Handler\HelloWorldHandler
        tags:
            - {name: messenger.message_handler}
              
  • Add extra api endpoint with jms serializer and default symfony logger
json_rpc_api:
    handlers:
        main:
            path: /api
            host: ~
            serializer: ~
            context: ~
            logger: ~
            error_handler: ~
        auth:
            path: /auth
            host: ~
            serializer: json_rpc_api.serialzier.jms
            context: ~
            logger: monolog.logger
            error_handler: ~
  • Add custom serializer adapter
composer require jms/serializer-bundle
services:
    json_rpc_api.serialzier.custom:
        class: Insidestyles\JsonRpcBundle\Server\Adapter\Serializer\CustomSerializer
        arguments:
            - "@serializer"
  • Add custom serializer adapter
services:
  Insidestyles\\Core\\Exceptions\\ApiErrorHandler:
    class: 'Insidestyles\Core\Exceptions\ApiErrorHandler'
    tags:
      - { name: 'json_rpc_api.error_handler' }
<?php

namespace Insidestyles\Core\Exceptions;

use Doctrine\ORM\EntityNotFoundException;
use Insidestyles\JsonRpcBundle\Server\ErrorHandler\Handler\ErrorHandlerInterface;
use Throwable;

class ApiErrorHandler implements ErrorHandlerInterface
{

    private const SYSTEM_ERRORS = [
        EntityNotFoundException::class,
    ];

    public function parse(Throwable $e): array
    {
        if (!$this->isSupported($e)) {
            return [];
        }
        return [
            'code' => $e->getCode(),
            'message' => $e->getMessage(),
            'data' => [],
        ];
    }

    public function isSupported(Throwable $e): bool
    {
        return $e instanceof IsExceptionInterface || in_array(get_class($e), static::SYSTEM_ERRORS);
    }
}
  • Enable jms serializer
json_rpc_api:
    handlers:
        main:
            path: /api
            host: ~
            serializer: json_rpc_api.serializer.jms
            context: json_rpc_api.serializer.default_context            
            logger: ~
            error_handler: ~

Tips

  • Install Symfony Validator and validation middle ware from messenger bus for message validation
framework:
    messenger:
        buses:
            command_bus:
                middleware:
                    - messenger.middleware.validation
<?php

namespace Insidestyles\JsonRpcBundle\Message;

use Symfony\Component\Validator\Constraints as Assert;

/**
 * @author Fuong <insidestyles@gmail.com>
 */
class HelloWorldMessage
{
    /**
     * @Assert\NotBlank()
     * @var string
     */
    private $message;

    public function __construct(string $message)
    {
        $this->message = $message;
    }

    /**
     * @return string
     */
    public function getMessage(): string
    {
        return $this->message;
    }
}
  • You don't have to extend class AbstractApi if you don't want to use Symfony Messenger. Just implement your own interface that extends JsonRpcApiInterface. See example HelloWorldApi

  • Go to api endpoint http:://localhost/api to see json-rpc methods

  • simple request content

{
    "id": 1,
	"method": "main.helloWorld",
	"params": {
		"name": "test"
	}
}
  • batch request content
[
    {
        "id": 1,
        "method": "main.helloWorld",
        "params": {
            "name": "hello1"
        }
    },
    {
        "id": 2,
    	"method": "main.helloWorld",
    	"params": {
    		"name": "hello2"
    	}
    }
]
  • using remote service with other api endpoints

Add requirement:

composer ocramius/proxy-manager

Update service

    hello.remote_services.hello:
        tags:
            -   name: 'json_rpc_remote_service'
                url: '%hello.api_server_url%'
                class: Insidestyles\JsonRpcBundle\Sdk\Contract\HelloWordJsonRpcApiInterface

Now you can call api

    $container->get('hello.remote_services.hello')->helloWorld('Hi');