Для розробників

← Для розробників

Ashterix

docs: rewrite JsonRpcBundle docs, add SDK docs, move them under docs/api

uk/docs/api/json-rpc-bundle/developers/README.md новий файл +122 −0

Для розробників

JsonRpcBundle — не закритий продукт «все в одному», а ядро, на якому можна будувати власні рішення. Він закриває основу будь-якого RPC API: прийом запитів, карту методів, валідацію, конвертацію даних, безпеку, кеш і документацію. Усе, що виходить за ці межі, — нові транспорти, протоколи, інтеграції, інструменти — задумано як розширення.

Цей розділ для тих, хто хоче зрозуміти, як бандл працює всередині, і розширювати його: у власному проєкті чи окремим пакетом для спільноти.

Принципи, на яких побудовано бандл

Код — єдине джерело правди. Методи API — це звичайні PHP-методи. Назви, типи, PHPDoc, атрибути й обмеження валідації одночасно визначають поведінку і документацію, тож вони не розходяться.

Мінімум налаштувань. Достатньо реалізувати IRpcService — решту бандл виводить сам: карту методів, схеми параметрів і результатів, конвертацію типів. Конфігурація потрібна лише там, де є реальний вибір.

Незалежність від транспорту. Процедура не знає, звідки прийшов запит: HTTP, консоль, черга повідомлень, REST чи MCP через розширення. Валідація, безпека, кеш і події однакові для всіх.

Відкритість до розширення. Ключові етапи обробки — події, а основні механізми — інтерфейси з автоконфігурацією: конвертери параметрів, генератори схем, джерела методів, стратегії batch, валідатори токенів, завантажувачі маршрутів. Нову поведінку додають, не змінюючи ядра.

Рідні механізми Symfony. DI-контейнер, EventDispatcher, Messenger, Lock, Validator, Cache, Translation — бандл не винаходить власних аналогів, тож розширення пишуться звичними для Symfony способами.

Відповідність стандарту. Протокол — JSON-RPC 2.0, документація — OpenRPC. Клієнти й інструменти, що підтримують стандарти, працюють з API без адаптації.

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

Що є в розділі

Загальні положення для розширень

  1. Не дублюйте ядро. Розширення не повинне мати власної карти методів, валідації чи формату помилок. Методи беруться з ServiceMap / IServiceHolder, виконання — через RpcExecutor, помилки — через rpc.error. Тоді #[RPC\Assertions], #[RPC\Cache], #[RPC\Lock], конвертери й події працюють для вашого транспорту автоматично.
  2. Поважайте групи й версії API. Визначайте групу з маршруту чи конфігурації й записуйте її в ApiGroupContext; передавайте версію в RpcRequest.
  3. Перевіряйте токен самі. RpcExecutor токен не перевіряє. Використовуйте IRpcSecurity з відповідним токен-холдером — так діятимуть ті самі security.providers, що й для основного API.
  4. Реєструйте маршрути через імпорт ядра. Тоді кожен імпорт для окремої групи отримує унікальні назви маршрутів.
  5. Залежність від ядра — ufo-tech/json-rpc-bundle: ^10.4.2 або новіше, якщо використовуєте RpcExecutor та IApiRouteImport.
  6. Компоненти, що створюються під час компіляції (IServiceFiller, IConstraintGenerator, IParamConvertor), бандл інстанціює сам під час збирання контейнера. Їхні конструктори можуть приймати лише сервіси, доступні на етапі компіляції, або теговані колекції — не скалярні параметри.

Точки розширення

Що Як Для чого
Routing\IApiRouteImport автоконфігурація, тег ufo.rpc.route_import Підключити router.yaml розширення окремо для кожної групи API: getResource(), getRouteNamePrefixAttribute()
Routing\RpcYamlFileLoader / ApiYamlFileLoader успадкування, тег routing.loader Старіший спосіб власного завантажувача маршрутів
Server\RpcExecutor автовайринг execute(IRpcRequestCarrier): RpcResponse — виконати запит повним циклом ядра
Server\RequestPrepare\IRpcRequestCarrier / IRpcHttpCarrier реалізація Обгортка вашого вхідного запиту. IRpcHttpCarrier::getHttpRequest() прив'язує rpc.post_response до HTTP-запиту й дозволяє від'єднане виконання notifications
Server\ServiceMap\IServiceHolder тег rpc.service_holder (вручну) Власне джерело методів або фільтр поверх ServiceMap
Security\Interfaces\IRpcSecurity, IRpcTokenHolder аліас / реалізація Перевірка токена з вашого джерела (заголовок, параметр, повідомлення)
Security\Interfaces\ITokenValidator аліас або security.providers Власна перевірка токенів
ParamConvertors\IParamConvertor автоконфігурація, тег rpc.param_convertor Конвертація власних типів параметрів і результатів
...\Reflections\Fillers\AbstractServiceFiller автоконфігурація, тег ufo-rpc.service-iterator Читання власних атрибутів методів у метадані Service
...\Generate\Interfaces\IConstraintGenerator тег rpc.constraint JSON Schema для власних обмежень валідації
Server\Batch\IBatchStrategy автоконфігурація, тег rpc.batch_strategy Власна стратегія виконання batch
DocAdapters\Outputs\AbstractPostmanAdapter успадкування Колекція Postman для вашого транспорту
Server\RpcLocaleNegotiator автовайринг Вибір мови з Accept-Language для власної документації
translations.paths prependExtensionConfig() Переклади назв і описів методів, які постачає розширення
Події #[AsEventListener] Поведінка навколо виконання методів

Мінімальний адаптер

// маршрути розширення для кожної групи API
final class AcmeRouteImport implements IApiRouteImport
{
    public function getResource(): string { return __DIR__.'/../../config/router.yaml'; }
    public function getRouteNamePrefixAttribute(): string { return '_acme_name_prefix'; }
}

// контролер розширення
final class AcmeController
{
    public function __construct(
        private RpcExecutor $executor,
        private IRpcSecurity $security,
    ) {}

    public function __invoke(Request $request): JsonResponse
    {
        $this->security->setTokenHolder(new HttpTokenHolder(/* ... */));
        $this->security->isValidApiRequest();

        $response = $this->executor->execute(new RpcFromAcme($request));

        return new JsonResponse(/* серіалізований $response */);
    }
}
// переклади, що постачає розширення
public function prepend(ContainerBuilder $container): void
{
    $container->prependExtensionConfig('ufo_json_rpc', [
        'translations' => ['paths' => [__DIR__.'/../../translations']],
    ]);
}

Живі приклади — у коді mcp-bundle і rest-bundle (див. Розширення).

Розвиток екосистеми

Ми всіляко заохочуємо розвиток екосистеми навколо бандла. Кожен новий транспорт, адаптер чи інструмент робить JSON-RPC на Symfony зручнішим для всіх.

Пишіть розширення. Якщо вам бракує інтеграції — з брокером повідомлень, протоколом, системою моніторингу чи генератором клієнтів, — оформіть її окремим пакетом за загальними положеннями вище. Розкажіть про нього — і ми додамо його до переліку розширень.

Повідомляйте про проблеми. Знайшли помилку чи нестиковку з документацією — створіть issue в репозиторії бандла. Підтверджені проблеми ми описуємо в розділі Відомі помилки.

Пропонуйте зміни в ядро. Якщо розширенню не вистачає точки розширення, це сигнал, що її варто додати в ядро. Порядок співпраці описано в CONTRIBUTING.md:

  1. Зробіть fork і окрему гілку.
  2. Перед роботою перевірте issue tracker; якщо обговорення немає — створіть issue з пропозицією.
  3. Дотримуйтесь стилю коду проєкту.
  4. Додайте тести для нових можливостей; усі наявні тести мають проходити.
  5. Опишіть у pull request, яку проблему вирішено або що додано, і будьте готові до обговорення.

Беручи участь у проєкті, ви погоджуєтесь дотримуватись правил поведінки.

Про вразливості безпеки повідомляйте не через публічні issue, а за контактом із SECURITY.md репозиторію.