Групи API

Групи API

Доступно з версії 10.2. Застосунки без груп працюють як раніше: усе належить до групи за замовчуванням general.

Групи дозволяють мати в одному застосунку кілька RPC API — наприклад, публічний для клієнтів, внутрішній для адмінки та окремі BFF. Кожна група має свою адресу, набір методів, версії, документацію та, за потреби, свою перевірку токенів.

Точки входу

Імпортуйте маршрути бандла один раз для кожного API. prefix задає адресу, а defaults.api_group — групу (без нього — general):

# config/routes/ufo_json_rpc.yaml
ufo_json_rpc:
    resource: ../../vendor/ufo-tech/json-rpc-bundle/config/router.yaml
    prefix: /rpc
    trailing_slash_on_root: false

ufo_json_rpc_internal:
    resource: ../../vendor/ufo-tech/json-rpc-bundle/config/router.yaml
    prefix: /rpc/internal
    defaults:
        api_group: internal
    trailing_slash_on_root: false

ufo_json_rpc_public:
    resource: ../../vendor/ufo-tech/json-rpc-bundle/config/router.yaml
    prefix: /rpc/public
    defaults:
        api_group: public
    trailing_slash_on_root: false

POST /rpc/internal виконує запит, GET /rpc/internal повертає OpenRPC, GET /rpc/internal/postman — Postman; версійні адреси — /rpc/internal/v2 тощо. Документація групи містить лише її методи й версії.

Назви маршрутів отримують префікс групи: general_ufo_rpc_api_server, internal_ufo_rpc_api_server, … Старі назви без префікса лишаються аліасами для general, тож router->generate('ufo_rpc_api_server') працює як раніше.

#[RPC\APIGroups]

Атрибут на класі або методі визначає, до яких груп належить метод:

public function __construct(array $groups = [], bool $withDefault = true)

withDefault: true додає групу general, false — ні.

use Ufo\JsonRpcBundle\ApiMethod\Interfaces\IRpcService;
use Ufo\RpcObject\RPC;

#[RPC\Info('catalog')]
#[RPC\APIGroups(['internal', 'public'], false)]
class CatalogApi implements IRpcService
{
    public function list(): array { /* ... */ }                  // internal і public

    #[RPC\APIGroups(['internal'], false)]
    public function updatePrice(int $productId, int $price): true { return true; } // лише internal

    #[RPC\APIGroups(['public'], false)]
    public function featured(): array { return [1]; }             // лише public

    #[RPC\APIGroups()]
    public function status(): string { return 'ok'; }             // лише general

    #[RPC\APIGroups(['internal'], false)]
    #[RPC\IgnoreApi]
    public function rebuildIndex(): true { return true; }         // ніде не публікується
}
Метод /rpc (general) /rpc/internal /rpc/public
catalog.list — так так
catalog.updatePrice — так —
catalog.featured — — так
catalog.status так — —
catalog.rebuildIndex — — —

Правила:

  • атрибут методу повністю замінює групи класу; без атрибутів метод належить до general;
  • APIGroups([], false) не публікує метод у жодній групі; #[RPC\IgnoreApi] має пріоритет над групами;
  • general — це не «усі групи», а звичайна група за замовчуванням;
  • карти методів і версії розділені за групами: метод іншої групи повертає Method not found;
  • для HTTP групу визначає маршрут, а не поле в JSON.

Токени для груп

Без додаткових налаштувань усі групи перевіряє базовий валідатор (security.clients_tokens або ваш ITokenValidator). Окрему перевірку для груп задає security.providers. Кожен провайдер має рівно один з параметрів service або clients_tokens і непорожній api_groups.

ufo_json_rpc:
    security:
        protected_api: true
        token_name: 'Ufo-RPC-Token'
        clients_tokens:
            - '%env(resolve:UFO_API_TOKEN)%'        # general та групи без провайдера
        providers:
            internal:
                api_groups: [internal]
                clients_tokens:
                    - '%env(resolve:UFO_INTERNAL_API_TOKEN)%'
            public:
                service: App\Security\UserTokenValidator   # реалізує ITokenValidator
                api_groups: [public]
  • Провайдер замінює базову перевірку для своїх груп; якщо він відхилив токен, базова перевірка не запускається.
  • Два провайдери для однієї групи, відсутній сервіс або клас без ITokenValidator — помилка компіляції контейнера.
  • protected_api, protected_doc і token_name спільні для всіх груп; захищена документація перевіряється провайдером своєї групи.

Консоль і async

bin/console ufo:rpc:process '{"jsonrpc":"2.0","id":1,"method":"catalog.updatePrice","params":{"productId":1,"price":100}}' \
    --api-group=internal --ver=v1

Дочірні процеси batch зберігають групу й версію маршруту. Для Symfony Messenger групу передають явно:

$message = new \Ufo\RpcObject\RpcAsyncRequest($request, $token, apiGroup: 'internal');

Повідомлення без групи виконуються в general.

Переклади для групи

Назви й описи методів у документації можна перевизначити для окремої групи — файлами translations/rpc/<group>.<locale>.yaml. Див. Документація API.