Rest 26.1200.0–26.1300.0: строгие типы REST V3 и лимит времени SQL
Ломающее обновление
Удалены или изменены публичные API — прикладной код может перестать работать.
Две версии Rest подряд закручивают гайки. В 26.1200.0 REST V3 перестал прощать "42" вместо 42, а права приложений переехали из ORM-поля в отдельную таблицу. В 26.1300.0 появился лимит времени SQL для REST-вызовов, исчез старый LoadLimiter, а параметры встраивания ограничены 2048 байтами. Если у вас интеграции на V3 или код, который читает AppTable, прогоните их на тестовом портале до обновления.
Новое
Ограничьте долгие SQL-запросы REST
В 26.1300.0 у модуля появились две опции. sql_query_time_limit_active включает лимит для старого REST и V3, по умолчанию он выключен. sql_query_time_limit задаёт секунды: по умолчанию 30, ноль снимает ограничение. Работает на MySQL от 5.7.8 и MariaDB от 10.1.1.
use Bitrix\Main\Config\Option;
Option::set('rest', 'sql_query_time_limit_active', 'Y');
Option::set('rest', 'sql_query_time_limit', '10');
Лимит ставится на SQL-сессию только на время вызова, потом возвращается DEFAULT. Общую длительность HTTP-запроса он не режет. Если запрос не уложился, клиент получит HTTP 503 с Retry-After, равным заданному числу секунд. Клиенту стоит уважать этот заголовок:
const response = await fetch(url, { method: 'POST', body });
if (response.status === 503) {
const delay = Number(response.headers.get('Retry-After') ?? 30);
await new Promise((resolve) => setTimeout(resolve, delay * 1000));
// повторить запрос
}
При ограничении нагрузки V3 тоже отдаёт Retry-After: оставшееся время блокировки в Redis или 300 секунд. На ответы 429 старого REST этот заголовок приходит не всегда.
Разрешите сотрудникам управлять своими встраиваниями
С 26.1200.0 в настройках REST есть политика ManageOwnEmbeddings. Личное приложение проходит три проверки: владелец, эта политика и доступ к приложению. Локальному нужны право создания и доступ. Администратора политика не ограничивает, обработчики placement тоже учитывают владельца и права приложения. В 26.1300.0 сотрудник без прав администратора может редактировать свою интеграцию, если проходит проверки доступа и preset не закрыт для всех, кроме администраторов.
Из кода политику сохраняет Bitrix\Rest\Public\Command\Embedding\AccessPolicy\SetOwnEmbeddingAccessCommand, читает AccessPolicyProvider::getAccessCodesAllowedToManageOwnEmbeddings(). Ошибка POLICY_AUDIT_FAILED значит, что политика сохранена, но запись в аудит не удалась: повторять сохранение не нужно.
Посчитайте лимиты batch заново
С 26.1200.0 ограничитель нагрузки считает legacy-batch одним вызовом: вложенные запросы больше не тратят лимит по отдельности и не возвращают свои сведения о нём. time.operating_reset_at теперь считается по границе окна учёта, при активной блокировке он, как и раньше, показывает её окончание.
В 26.1300.0 подстановки batch внутри fields и правых частей filter приводятся к типам DTO, включая вложенные структуры. Строка "42" станет int, если обратное преобразование даёт ту же строку. "042", -0 и числа за пределами int остаются строками. Обычных JSON-значений это не касается, их по-прежнему нужно передавать в правильном типе.
Меню приложений и локальная сеть
MenuApplicationProvider::getForWeb() и getForMobile() в 26.1200.0 отдают доступные пользователю приложения с локализованными названиями, мобильный список требует MOBILE=Y. В списке установленных приложений права пользователя проверяются до пагинации. В 26.1300.0 iframe приложения получил разрешения локальной сети для своего origin: в Chrome 142 и новее приложение может обращаться к устройствам локальной сети, если это разрешил браузер.
Что сломается
Передавайте в REST V3 значения правильного типа
С 26.1200.0 int-поле в fields отклоняет строку "42" и дробное число. String принимает только строку, bool только true/false (не 0/1), float принимает float и int. Несуществующая дата 2026-02-31 больше не превращается в 3 марта. Чаще всего ломается код, который отдаёт в API строки из $row как есть:
$fields = [
'id' => (int) $row['ID'],
'active' => $row['ACTIVE'] === 'Y',
'price' => (float) $row['PRICE'],
'title' => (string) $row['TITLE'],
];
У int-параметров самого запроса своя проверка: она отклоняет boolean, дробные числа, нецелые числовые строки и float больше 2**53.
Права из grant теперь проверяются в filter, order, fields, cursor и агрегатном select. Пустой select: [] больше не обходит scope, а запрещённые поля верхнего уровня вырезаются из ответа, id остаётся. Если интеграция получала поле, на которое у неё нет права, после обновления она его не увидит. В 26.1300.0 ту же проверку пустого select распространили на нестандартные структуры, кроме агрегатной.
Замените обращения к PHP API
У Bitrix\Rest\AppTable с 26.1200.0 нет ORM-поля ACCESS, запросы с ним и ORM-геттер getAccess() падают. Права приложения по-прежнему отдаёт getByClientId():
use Bitrix\Rest\AppTable;
$app = AppTable::getByClientId($clientId);
$access = $app['ACCESS'] ?? null;
Записывает их AppTable::setAccess($appId, $rights).
AddEmbeddingCommandHandler::__invoke() из Bitrix\Rest\Public\Command\Application\Embedding при ошибке placement.bind с 26.1200.0 бросает Bitrix\Rest\RestException вместо PersistenceException. Старый catch (PersistenceException) его не поймает.
В 26.1300.0 удалён Bitrix\Rest\Engine\Access\LoadLimiter, алиаса нет. Новый Bitrix\Rest\V3\Limiter\LoadLimiter работает через объект с методами check, start, finish и зависимостями в конструкторе, а цепочку лимитеров собирает LimiterChainFactory. Заменой namespace статические вызовы не спасти, код придётся переписать.
Проверьте встраивания и установку приложений
С 26.1300.0 placement.bind и запись PlacementTable.OPTIONS отклоняют JSON длиннее 2048 байт. Ядро меряет strlen(Json::encode($options, 0)), хотя в тексте ошибки написано characters. Без флага JSON_UNESCAPED_UNICODE каждая кириллическая буква превращается в \uXXXX и занимает шесть байт, так что русские подписи упираются в лимит примерно на 340 символах. Проверить заранее можно тем же методом, которым пользуется ядро:
use Bitrix\Rest\PlacementTable;
$check = PlacementTable::validateOptionsLength($options);
if ($check !== true) {
throw new \LengthException($check);
}
У собственных V3-контроллеров автоматические маршруты <resource>.field.custom.list/get/delete/update/add теперь создаются, только если в #[FieldAccess] DTO указан провайдер доступа. Обычные .field.list/get и явно объявленные маршруты остаются.
Marketplace\Application::install() получил шестой аргумент bool $createSystemUser = false. Чтобы новая или неактивная установка могла создать системного пользователя, передайте true при включённой опции allow_create_sys_user:
use Bitrix\Rest\Marketplace\Application;
$result = Application::install($code, createSystemUser: true);
Старый вызов без аргумента получит отказ. У уже активного приложения решение не перезаписывается, а если атрибута нет, при включённой общей опции действует прежнее разрешение.
user.update в 26.1300.0 отклоняет массивы и неподходящие объекты в строковых полях, принимает scalar, null и Stringable, файловые PERSONAL_PHOTO и WORK_LOGO проверка не трогает. В MESSAGE_ID при подтверждении offline-событий допустимы только scalar-элементы массива, null нельзя. Описание шага в конструкторе форм выводится текстом: если вы вставляли туда HTML, он покажется как разметка.
БД
С 26.1200.0 права приложений лежат в b_rest_app_access: ID, APP_ID, ACCESS_CODE varchar(100), уникальный индекс (APP_ID, ACCESS_CODE). На нашем обновлённом эталоне столбец b_rest_app.ACCESS в базе остался, но ORM его больше не описывает. Если вы читали права прямым SQL из b_rest_app, переключитесь на новую таблицу или на getByClientId().
В 26.1300.0 решение CREATE_SYSTEM_USER хранится в атрибутах приложения. Невалидный JSON в PlacementTable.OPTIONS при чтении через ORM превращается в [].
Мелочи и находки
- В 26.1200.0 фильтр
IN []больше не генерирует SQLIN (), а структурированные фильтры проходят те же преобразования, что обычные. В 26.1300.0 ORM сохраняет именаUF_*без смены регистра. - MCP в 26.1200.0 проверяет поля по грамматике REST-структур и возвращает имена полей с ошибками, nullable-параметры без значения по умолчанию перестали быть обязательными. В 26.1300.0 агрегатный
selectописан в схеме как объект функций,hiddenFieldsиfieldWhitelistдействуют и на агрегаты, пустые аргументы больше не подхватывают тело внешнего HTTP-запроса. - Импорт конфигурации в 26.1200.0 повторно проверяет доступ к выбранному манифесту и берёт
MANIFEST_CODEс сервера. Локализованные названия очищаются после успешного сохранения приложения. - В 26.1300.0 исключение в callback при закрытии приложения из боковой панели больше не роняет страницу, оно уходит в
BX.debug.
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
Bitrix\Rest\AppTable.ACCESS
|
Удалено |
Bitrix\Rest\AppTable::getByClientId() / Bitrix\Rest\AppTable::setAccess()
|
Bitrix\Rest\Engine\Access\LoadLimiter
|
Удалено |
Bitrix\Rest\V3\Limiter\LoadLimiter
|