Попробовать API
</>
Zero-dependency SDK, open-source и партнёрский API
platformaРазбор
14 мин

Zero-dependency SDK, open-source и партнёрский API

TL;DR: один SDK с 14 транзитивными зависимостями отрезает половину интеграторов ещё на `composer require`, а закрытый репозиторий — на security-ревью покупателя. Разбираем три инженерных решения, которые превращают публичный API в платформу: zero-dependency SDK на stdlib, открытый исходный код на `github.com/BOTIX-pro/*` и партнёрский слой с sub-проектами и жёсткой изоляцией данных. Факты — по реальному Public API v1 BOTIX, секреты замаскированы.

Коротко

  • Zero-dependency SDK — не про красоту, а про риск. Три SDK BOTIX (PHP, Python, Node) собраны только на stdlib: composer audit / npm audit / safety check зелёные по дизайну, а не по везению.
  • Open-source снимает главный блокер корпоративной сделки: security проходит SDK за час по GitHub вместо двух недель NDA, а баг чинится через PR, а не через тикет.
  • Партнёрский слой — это не отдельный продукт, а набор архитектурных свойств (отдельный тип ключа, sub-проекты, Auth::assertProjectAccess(), отдельный набор эндпоинтов), которые закладываются заранее, иначе изоляция данных потечёт на первой ошибке.

Три решения из заголовка не связаны техническим стеком, но связаны одной задачей: снять трение на входе для того, кто ставит ваш код себе в продакшен. Ниже — каждое отдельно: суть, конкретика по Public API v1 BOTIX и разбор границ, где решение работает, а где нет.

BOTIX — российская платформа AI-ассистентов для бизнеса. Public API v1 в проде на api.botix.pro/public/v1/*, документация (Redoc) — на developers.botix.pro, три открытых SDK (PHP, Python, Node), CLI и example-приложения (Laravel, Express, Flask) — в организации github.com/BOTIX-pro.

Zero-dependency SDK: почему 14 зависимостей — это чужой техдолг

Команда подключает сторонний API. Видит composer require botix-pro/sdk (или pip install, или npm install), ставит. Через минуту в composer.lock появляется не одна новая строка, а пятнадцать: SDK притащил HTTP-клиент, JSON-валидатор, библиотеку для UUID, retry-механизм, ещё один логгер и пару утилитарных пакетов, которые поддерживает один мейнтейнер в свободное время.

Каждая транзитивная зависимость создаёт ровно три класса проблем:

  1. Конфликты версий. SDK тянет requests==2.28.0, у интегратора уже стоит requests==2.31.0 из-за собственного фреймворка. Жёсткий pin — установка падает с конфликтом. Мягкий (>=2.20,<3.0) — встанет одна из совместимых версий, и обновление фреймворка через полгода сломает совместимость. В Python это особенно болезненно: глобальное пространство имён не позволяет держать две версии requests одновременно. В Node за счёт node_modules per-package чуть легче, но дубли раздувают бандл.
  2. Supply-chain атаки. Каждая транзитивная зависимость — потенциальный вектор: event-stream (доступ передан незнакомцу, добавившему кражу кошельков), ua-parser-js (взлом аккаунта мейнтейнера, майнер в релизе), colors.js (протест-релиз, ломающий всё зависимое). Когда SDK тянет 14 зависимостей, число транзитивных пакетов в дереве переваливает за 100 — и npm audit / safety check регулярно ругаются на advisories в зависимостях зависимостей, которые интегратор пофиксить не может: он не контролирует SDK.
  3. Устаревание. Зависимости стареют. Свежая год назад сегодня имеет известную уязвимость. SDK с заброшенными зависимостями — мина под интегратором.

Наше решение — zero-dependency: SDK использует только стандартную библиотеку языка и ничего больше. Никаких requests, axios, guzzlehttp/guzzle. В PHP — curl через ext-curl (входит в стандартную поставку). В Python — urllib.request из stdlib. В Node — встроенные https и http.

Полный composer.json PHP-SDK без сокращений — на github.com/BOTIX-pro/sdk-php/blob/main/composer.json:

json
{
    "name": "botix-pro/sdk",
    "description": "Official BOTIX SDK for PHP",
    "type": "library",
    "license": "MIT",
    "require": {
        "php": "^8.2",
        "ext-curl": "*",
        "ext-json": "*"
    },
    "require-dev": {
        "phpunit/phpunit": "^10.5",
        "phpstan/phpstan": "^1.10"
    },
    "autoload": {
        "psr-4": {
            "Botix\\": "src/"
        }
    }
}

Секция require — нулевая (только сам PHP и встроенные расширения). У Python-SDK requirements.txt пустой, у Node-SDK секция dependencies в package.json нулевая (только devDependencies для билд-инструментов, которые в продакшен не попадают). Для сравнения: типичный SDK другого вендора — 14 строк в require, 47 транзитивных зависимостей в дереве, 12 advisories в composer audit после года жизни.

Возражение «но requests удобнее urllib, зачем городить с stdlib» справедливо для прикладного кода. SDK — не прикладной код. Он живёт у интегратора в продакшене, и его задача — не быть красивым, а минимизировать риск для того, кто его установит.

Технически zero-dependency несложно: HTTP-клиент в stdlib покрывает 95% сценариев (GET/POST/PUT/DELETE, заголовки, тело, чтение ответа); HTTP/2 multiplexing и connection pooling публичному API через интернет не нужны. JSON-сериализация есть везде из коробки, UUID — тоже (или 10 строк кода), retry — цикл с экспоненциальным бэкоффом на полчаса работы. Сложнее становится тестирование (моки HTTP через урезанный stdlib-клиент пишутся вручную) — это решается тем, что все три SDK генерируются openapi-generator-cli из единого openapi.yaml, шаблоны настроены один раз, и сгенерированный код идентичен по структуре во всех трёх языках. Про генератор и white-label подробнее — в разборе SDK из OpenAPI: генератор, white-label, open-source.

Как проверить SDK перед установкой

Быстрая эвристика — открыть package.json / composer.json / setup.py на GitHub и посмотреть размер секции зависимостей:

  • 0–2 пакета — SDK с уважением к интегратору.
  • 5–7 — приемлемо, но проверьте, что зависимости мейнстрим, а не маргинальные пакеты от одного автора.
  • 10+ — SDK, который кладёт на вас груз поддержки чужой экосистемы.

Установка zero-dependency SDK перестаёт быть событием в логе CI/CD: одна строка, одна папка, никаких конфликтов. Размер бандла Node-приложения после @botix/sdk растёт на 30–40 КБ, а не на 2 МБ.

Open-source SDK: пять функций, а не «щедрость»

Вопрос «открывать ли исходники SDK» в большинстве команд обсуждают через категорию щедрости: «принесём пользу сообществу» против «лучше потратим время на фичи». В таком виде спор не приходит к решению — обе стороны рассуждают о морали, а не о бизнесе. На деле open-source SDK — инструмент с конкретными функциями, каждую из которых стоит считать отдельно.

Функция первая: security-аудит без участия поставщика. Корпоративная интеграция почти всегда проходит через security-команду. Закрытый SDK для них — чёрный ящик, который что-то делает с данными. Дальше три варианта, все дорогие: заблокировать интеграцию (частый исход); потребовать SOC 2 Type II, ISO 27001 и DPA (месяцы и десятки тысяч долларов); попросить исходники под NDA (две недели ожидания). Open-source закрывает их одним движением: security открывает GitHub, видит, что библиотека делает только заявленное, и пропускает. SOC 2 всё равно нужен — для инфраструктуры и процессов, но SDK как точка входа в чужой код становится прозрачным. SDK на github.com/BOTIX-pro/sdk-php (Composer-пакет botix-pro/sdk, тег v1.1.0) проходит проверку покупателя за час вместо двух недель — ещё до того, как мы получаем сигнал, что нами интересуются. Корпоративный sales-цикл сокращается на месяцы.

Функция вторая: bug fix не блокируется вендором. В закрытом SDK любая ошибка — тикет в поддержку и новая версия через месяц-три. В open-source два варианта: сам сделать PR либо временно форкнуть и патчить через VCS-ссылку в composer.json/package.json, пока upstream не примет фикс. Никакой блокировки. На стороне поставщика это переводит багфиксы в режим «принять PR» вместо «диагностировать и исправлять самим».

Функция третья: сигнал зрелости API. Открытая лицензия — сигнал, что у API есть стабильный контракт, который не стыдно показать. Закрытый SDK читается как «наколхозили, поэтому прячут». Три SDK BOTIX имеют одинаковую структуру методов и синхронные мажорные версии:

composer require botix-pro/sdk:^1.1
pip install botix==1.1.0
npm install @botix/sdk@1.1.0

Если разработчик переключается между языками, переучиваться не нужно — структура client.contacts.create(...) одинакова в PHP, Python и Node. Все три генерируются openapi-generator-cli из единого openapi.yaml — машинно-читаемой точки правды.

Функция четвёртая: контрибьюции от сообщества. На ранних этапах open-source SDK — односторонняя отдача. По мере роста появляются PR с типичными улучшениями (retry, timeout, прокси, совместимость с нетипичной версией). У зрелых поставщиков (Stripe, Twilio, Slack) — десятки внешних контрибьюторов. SDK BOTIX молодые, контрибьюций пока нет — оценка делается через 90 дней после релиза, это нормальный начальный режим.

Функция пятая: white-label-партнёры конвертируют наш SDK в свой. Партнёр — агентство или ISV — почти всегда требует исходники интегрируемых библиотек, иначе его security не пропустит встраивание в собственный продукт. С закрытым SDK у партнёра выбор: ждать NDA (пара недель) или уйти к конкуренту с открытым кодом. MIT-лицензия снимает вопрос: партнёр кладёт LICENSE в свой бандл, упоминает BOTIX в about-секции и встраивает SDK под своим брендом. Это прямой мост к следующему разделу — про архитектуру партнёрского слоя, которую мы разбираем отдельно в Зачем открывать SDK в open-source: 5 причин.

Сколько open-source стоит поставщику

Главный страх — что код «утащат». Утащить SDK без потери смысла невозможно: он бесполезен без API, к которому обращается; под чужой API переписать легче, чем переиспользовать. Второй страх — раскрытие архитектуры — решается дисциплиной: SDK не содержит бизнес-логики, он делает три вещи (формирует запрос, подписывает, парсит ответ), всё остальное — на стороне API. Открытый код тогда не раскрывает ничего сверх того, что и так лежит в OpenAPI-спецификации. Третий страх — поддержка: публичный репозиторий означает входящие issues, и без выделенного человека open-source SDK превращается в кладбище с просрочкой по 200 дней. У нас на это выделен один разработчик с 20–25% времени, около 50 человеко-часов в квартал.

Итог по трудозатратам: около 60 человеко-часов в месяц на три SDK + CLI + три example-приложения, плюс CI-матрица (4 версии PHP × 2 Python × 2 Node) и одноразовые публикационные ключи пакетных менеджеров (после использования отзываются — требование безопасности). Альтернатива — senior sales-инженер за 250–400 тысяч рублей в месяц. Открытый SDK стоит примерно столько же, но работает пассивным каналом доверия 24/7.

Когда open-source SDK не нужен

  • API нишевой, аудитория два-три интегратора, все по NDA — открывать ради абстрактной зрелости бессмысленно.
  • API в стадии активного breaking-change — сообщество увидит нестабильность в публичном репозитории, сигнал обратный ожидаемому.
  • Нет человека на review PR и ответы на issues — открытие ухудшит ситуацию.

Все три условия — про ранние стадии. Когда продукт зреет, API стабилизируется и ресурс появляется — открытие становится логичным шагом. В нашем случае все три были закрыты до публикации.

Что превращает API в платформу: партнёрский слой

Один эндпоинт /contacts не делает API платформой. Платформа начинается там, где появляется второй уровень: партнёр, встраивающий API внутрь своего продукта и продающий его дальше. У прямого клиента контур простой — один аккаунт, один проект, несколько ключей, один webhook. У партнёра он многоуровневый: сам партнёр имеет аккаунт у поставщика, внутри — десятки конечных клиентов, у каждого свой логический проект со своими данными, биллингом, webhook'ом и настройками.

Если удовлетворять партнёрскую модель тем же API, что и обычных клиентов, быстро упираешься в несовместимости: обычный ключ работает в контексте одного проекта, партнёрский — должен работать в контексте партнёрского аккаунта и переключаться между конечными. Минимальный набор свойств, который для этого закладывается:

  • Партнёрский уровень аутентификации. Отдельный тип ключа (partner key) с более высокими привилегиями, чем у обычного project key: создать проект, перечислить существующие, получить ключи. Обращение к партнёрским операциям с обычным ключом — 403.
  • Sub-проекты под одним партнёрским аккаунтом. Иерархия «партнёр сверху, конечные проекты снизу», каждый sub-проект — со своими данными, webhook'ом, биллингом.
  • OAuth installations с реселлерскими scope. Partner-scope позволяет OAuth-приложению, установленному в партнёрский аккаунт, видеть все sub-проекты, а не только тот, куда оно установлено напрямую.
  • Биллинг-события через API. Партнёр биллит по своей модели, ему нужны сырые данные (запросы, сообщения, активные контакты по каждому sub-проекту за период) — либо эндпоинт типа GET /partner/usage, либо webhook в конце расчётного периода.
  • Audit-логи на партнёрском уровне. Когда конечный клиент пишет «не работает», партнёр должен диагностировать сам, без поставщика — по журналу sub-проектов, регулируемому тем же partner-ключом.
  • Кастомные домены и брендирование. Сам API кастомного домена не требует, но если в партнёрском решении есть UI под брендом партнёра — нужны white-label-домены. В BOTIX этот пункт пока в плане; текущая партнёрская работа идёт через API без кастомного фронтенда.

Ключевая граница — изоляция данных. Внутри одного партнёрского аккаунта могут быть sub-проекты конкурирующих компаний, и возможность одного увидеть данные другого — катастрофа. Граница держится на трёх уровнях: на уровне БД — WHERE project_id = ? в каждом запросе; на уровне API — явный project_id и проверка принадлежности партнёрскому аккаунту; на уровне ключей — ответ по чужому sub-проекту по чужому ключу невозможен. В BOTIX это Auth::assertProjectAccess($projectId) в начале каждого эндпоинта, работающего с проектом (при попытке достать чужой ресурс возвращается 404, а не 403 — не утекает даже факт существования объекта). Партнёрский уровень добавляет слой: проверяется не только доступ к sub-проекту, но и что он принадлежит партнёрскому аккаунту, выпустившему ключ. Как та же изоляция multi-tenant выглядит с точки зрения OAuth и webhook — в разборе Партнёрский API: sub-проекты, изоляция и OAuth-scope.

Документация для партнёра — отдельная: в репозиториях botix-pro на GitHub это Postman/Bruno-коллекция с разделом «Partner API» (создание sub-проекта, получение ключа, перечисление проектов, выгрузка usage) — отдельный набор операций, не подмножество обычной коллекции.

Чек-лист готовности к партнёрской работе

Готовность оценивается за полчаса по короткому списку:

  1. Есть отдельный тип ключа с расширенными правами?
  2. Есть концепция sub-проектов?
  3. WHERE project_id = ? в каждом запросе?
  4. Auth::assertProjectAccess() в начале каждого эндпоинта?
  5. Отдельные scope для партнёров в OAuth?
  6. Способ получить сырые usage-данные через API?
  7. Аудит-журнал, доступный партнёру по всем sub-проектам?
  8. Отдельная документация и Postman-коллекция?

Если «нет» начинается с третьего пункта — API технически не готов к партнёрам. Если «да» на все — открывать можно без страха получить инцидент на первой неделе. Решение о партнёрском слое продуктовое, не техническое: не каждый API должен быть платформой. Но если решение принято, свойства закладываются с самого начала, а не на третьей итерации после первых жалоб.

Что не делать

  • Не навешивать партнёрские возможности на обычные эндпоинты через флаги «если ты партнёр, можешь передать ещё этот параметр» — запутанная семантика. Лучше отдельный префикс /partner/v1/*.
  • Не делать партнёрский API «по запросу» избранным по NDA. Работает, пока партнёров три; на двадцати — разные обещания, теневая документация, техдолг.
  • Не ставить высокий порог входа. На старте партнёрский слой — маленькие команды, экспериментирующие; из них и вырастают крупные.

Что это значит для интегратора

  1. Исходники SDK открыты на github.com/BOTIX-pro — security-проверка занимает час, не недели.
  2. Zero-dependency — composer audit, npm audit, safety check показывают чистый статус по дизайну.
  3. Один и тот же SDK API в трёх языках — миграция стека не требует переучивания.
  4. Нашли баг — можно сделать PR; торопитесь — форк и патч через VCS-ссылку, без блокировки через тикет.
  5. Строите продукт поверх BOTIX для своих клиентов — партнёрский слой (sub-проекты, изоляция, отдельная коллекция) закладывается заранее, а не докручивается после первого инцидента.