Полный цикл в digital

REST API в 1С-Битрикс: Управление сайтом (БУС)

Часто при разработке мобильных приложений или современных веб-интерфейсов для сайтов на «1С-Битрикс: Управление сайтом» (БУС) возникает необходимость получать и отправлять данные через REST API.

В отличие от Битрикс24, в БУС нет встроенного интерфейса для быстрой генерации ключей доступа к REST API. Для этого перейдите в административную панель Настройки > Настройки продукта > Модули, убедитесь что модуль rest установлен:

Настройка REST API

Официальная документация по REST API.

Создание интерфейса для управления вебхуками

Поскольку в БУС нет штатного раздела для генерации вебхуков, создадим свою административную страницу для этой цели. Чтобы избежать конфликтов с URL-адресами самого REST API, разместим эту страницу в каталоге /local/rest/:

/local/rest/index.php<?php
// подключаем пролог административной части Битрикса
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_admin.php');

// проверяем, что модуль REST установлен и активен
if (!\Bitrix\Main\Loader::includeModule('rest')) {
    ShowError('Модуль REST не установлен');
    require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_admin.php');
    exit;
} ?>

<div class="adm-workarea">

<?php
// выводим компонент REST API, отображает список вебхуков и обрабатывает страницы их создания/редактирования
$APPLICATION->IncludeComponent(
    'bitrix:rest.hook',
    '.default',
    [
        'SEF_MODE' => 'Y',
        // путь к нашей папке
        'SEF_FOLDER' => '/local/rest/',
        'COMPONENT_TEMPLATE' => '.default',
        // шаблоны ЧПУ для компонента
        'SEF_URL_TEMPLATES' => [
            'list' => '',
            'event_list' => 'event/',
            'event_edit' => 'event/#id#/',
            'ap_list' => 'ap/',
            'ap_edit' => 'ap/#id#/',
        ],
    ],
    false
); ?>
    <br>
    <a href="javascript:;" class="adm-btn adm-btn-green"
       onclick="BX.PopupMenu.show('rest_hook_menu', this, [
    {
        // ссылка на создание исходящего вебхука
        'href':'/local/rest/event/0/',
        'text':'Исходящий вебхук'
    },
    {
        // ссылка на создание входящего вебхука
        'href':'/local/rest/ap/0/',
        'text':'Входящий вебхук'
    }
    ])">
        Добавить вебхук
    </a>

</div>

<?php
// подключаем эпилог
require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_admin.php');
Настройка urlrewrite.php

Это критически важный шаг для того, чтобы и страница управления вебхуками и сами вызовы API работали корректно и не конфликтовали, необходимо иметь два отдельных правила:

  1. Правило для страницы управления вебхуками /local/rest/, указывающее на компонент
  2. Правило для API-вызовов /rest/, указывающее на стандартный обработчик Битрикса

Откройте файл urlrewrite.php в корне сайта и убедитесь, что он содержит следующие два правила в последовательности как в примере:

urlrewrite.php// правило для страницы управления вебхуками (с компонентом)
100 =>
array (
    // условие для нашего раздела управления
    'CONDITION' => '#^/local/rest/#',
    'RULE' => '',
    // ID Компонента ОБЯЗАТЕЛЬНО
    'ID' => 'bitrix:rest.hook',
    // путь к файлу с компонентом
    'PATH' => '/local/rest/index.php',
    'SORT' => 100,
),
// правило для стандартной обработки вызовов REST API
150 =>
array (
    // условие для вызовов API
    'CONDITION' => '#^/rest/#',
    'RULE' => '',
    // ID может быть пустым
    'ID' => '',
    // путь к стандартному обработчику
    'PATH' => '/bitrix/services/rest/index.php',
    'SORT' => 200,
),

Не забывайте очищать кеш Битрикса после внесения изменений в файлы PHP и urlrewrite.php

Генерация вебхука

Теперь, когда у нас есть страница управления, можно сгенерировать сам вебхук.

Перейдите по адресу https://site1.loc/local/rest/. Вы должны увидеть интерфейс для работы с вебхуками:

Нажмите зеленую кнопку Добавить вебхук и выберите Входящий вебхук:

Задайте имя вебхуку, в разделе Настройка прав доступа найдите и отметьте галочкой Информационные блоки (iblock). Также отметьте другие права, которые могут понадобиться вашему приложению, нажмите Сохранить:

Система сгенерирует URL для вызова REST API. Он будет выглядеть примерно так https://site1.loc/rest/ID_пользователя/уникальный_код/profile/, в действительности будет работать по адресу: https://site1.loc/rest/ID_пользователя/уникальный_код/:

Настройка инфоблока

Чтобы получить доступ к данным конкретного инфоблока через REST API, перейдите в настройки нужного инфоблока Контент -> Инфоблоки -> Типы инфоблоков -> (ваш тип) -> (ваш инфоблок), перейдите на вкладку Инфоблок, установите галочку Включен доступ через REST и задайте Символьный код API:

Базовый вызов API

Теперь можно попробовать получить данные элемента, используя метод iblock.Element.get.

URL вебхука:

https://site1.loc/rest/1/78103bqeped92b8c/

URL вебхука с параметрами:

https://site1.loc/rest/1/78103bqeped92b8c/iblock.Element.get?iblockId=37&elementId=555

По умолчанию метод iblock.Element.get возвращает очень ограниченный набор полей элемента:

  1. ID
  2. NAME
  3. IBLOCK_SECTION_ID

Расширение API с помощью своего контроллера

Чтобы обойти ограничения стандартного метода и получить доступ к полям вроде DETAIL_TEXT, необходимо создать собственный REST-контроллер для вашего инфоблока. Подробная документация об этом механизме доступна на сайте документации 1С-Битрикс своя реализация контроллера.

Мы реализуем контроллер, который наследует стандартный, но переопределяет список разрешенных полей.

Сохраните символьный код API инфоблока

В настройках нужного инфоблока на вкладке Инфоблок найдите поле Символьный код API, запомните его:

Создайте файл контроллера
/local/php_interface/lib/Rest/MyElementController.php<?php

namespace Local\Rest;

// пространство имен для логирования
// use Bitrix\Main\Diag\Debug;

// Убедитесь, что базовый класс доступен, проверка добавлена на случай проблем с загрузкой модуля
if (!class_exists('\Bitrix\Iblock\Controller\DefaultElement')) {
    // лог для отладки
    // Debug::writeToFile('Base DefaultElement class not found!', '', '__controller_error.log');

    return;
}

class MyElementController extends \Bitrix\Iblock\Controller\DefaultElement
{
    /**
     * Конструктор. Обязательно вызываем родительский.
     */
    public function __construct()
    {
        parent::__construct();
        // лог для отладки
        // Debug::writeToFile('MyElementController (full) instantiated!', '', '__controller_exec.log');
    }

    /**
     * Переопределяем список разрешенных полей, добавляя нужные нам.
     * Метод должен быть ПУБЛИЧНЫМ и СТАТИЧЕСКИМ (public static), как в родительском классе.
     * @return array
     */
    public static function getAllowedList()
    {
        // лог для отладки
        // Debug::writeToFile('MyElementController: static getAllowedList() called.', '', '__controller_exec.log');

        // вызов родительского статического метода для получения базового списка
        $allowed = parent::getAllowedList();
        // лог для отладки
        // Debug::writeToFile(['Parent allowed list' => $allowed], '', '__controller_exec.log');

        // Добавляем наши поля в список разрешенных, сюда можно добавить и другие нужные поля
        $allowed[] = 'DETAIL_TEXT';
        $allowed[] = 'PREVIEW_TEXT';
        $allowed[] = 'DETAIL_PICTURE';
        $allowed[] = 'PREVIEW_PICTURE';
        $allowed[] = 'CODE';

        // убираем дубликаты и возвращаем финальный список
        $finalAllowed = array_unique($allowed);
        // лог для отладки
        // Debug::writeToFile(['Final allowed list' => $finalAllowed], '', '__controller_exec.log');

        return $finalAllowed;
    }

    /**
     * Опционально: можно переопределить getAction, если нужна особая логика
     * Например, для дополнительной обработки данных перед возвратом.
     */
    /*
    public function getAction($iblockId, $elementId)
    {
        // лог для отладки
        // Debug::writeToFile('MyElementController: getAction() called.', '', '__controller_exec.log');

        $result = parent::getAction($iblockId, $elementId);
        // ваша кастомная логика обработки $result

        return $result;
    }
    */
}
Зарегистрируйте контроллер в системе
/local/php_interface/init.php<?php

use Bitrix\Main\Loader;
use Bitrix\Main\DI\ServiceLocator;
use Bitrix\Main\EventManager;
// пространство имен для логирования
// use Bitrix\Main\Diag\Debug;

// гарантируем, что модуль iblock загружен ПЕРЕД регистрацией, наш контроллер наследуется от класса из этого модуля
if (!Loader::includeModule('iblock')) {
    // лог для отладки
    // Debug::writeToFile('Failed to load iblock module in init.php!', '', '__init_error.log');

    return;
} else {
    // лог для отладки
    // Debug::writeToFile('Iblock module loaded successfully in init.php.', '', '__init_log.log');
}

// регистрируем автозагрузку для нашего контроллера, сообщаем Битриксу, где искать наш класс Local\Rest\MyElementController
Loader::registerAutoLoadClasses(null, [
    '\Local\Rest\MyElementController' => '/local/php_interface/lib/Rest/MyElementController.php',
]);

// регистрируем контроллер в Service Locator через событие OnPageStart
$eventManager = EventManager::getInstance();
$eventManager->addEventHandlerCompatible('main', 'OnPageStart', function() {
    try {
        // ВАЖНО замените 'my_iblock_1' на реальный API_CODE вашего инфоблока
        $apiKey = 'my_iblock_1';
        // формируем уникальный ключ для регистрации контроллера
        $key = 'iblock.element.' . $apiKey . '.rest.controller';

        // лог для отладки
        // Debug::writeToFile('OnPageStart: Attempting registration for key: ' . $key, '', '__controller_reg.log');

        // проверяем, что наш класс действительно доступен после автозагрузки
        if (class_exists('\Local\Rest\MyElementController')) {
            // создаем экземпляр локатора
            $serviceLocator = ServiceLocator::getInstance();
            // создаем экземпляр контроллера
            $instance = new \Local\Rest\MyElementController();
            // регистрируем локатор по ключу
            $serviceLocator->addInstance($key, $instance);

            // лог для отладки
            // Debug::writeToFile('OnPageStart: Controller registered successfully for key: ' . $key, '', '__controller_reg.log');
        } else {
            // лог для отладки
            // Debug::writeToFile('OnPageStart: Class \Local\Rest\MyElementController not found!', '', '__controller_reg_error.log');

            // дополнительная проверка базового класса для диагностики
            // if (!class_exists('\Bitrix\Iblock\Controller\DefaultElement')) {
            //     Debug::writeToFile('OnPageStart: Base \Bitrix\Iblock\Controller\DefaultElement STILL not found!', '', '__controller_reg_error.log');
            // }
        }
    } catch (\Throwable $e) {
        // ловим любые ошибки при регистрации
        // Debug::writeToFile('OnPageStart: Error during registration: ' . $e->getMessage(), '', '__controller_reg_exception.log');
    }
});

Не забудьте заменить my_iblock_1 на реальный API_CODE вашего инфоблока в этом файле!

Вызов API с расширенным набором полей

После создания и регистрации контроллера вы можете использовать параметр select в запросе iblock.Element.get для получения полей, добавленных в getAllowedList.

Пример GET-запроса для получения ID, NAME и DETAIL_TEXT:

https://site1.loc/rest/1/78103bqeped92b8c/iblock.Element.get?iblockId=1&elementId=34&select[0]=ID&select[1]=NAME&select[2]=DETAIL_TEXT

Добавление своих методов в REST API

Объявляем свой класс RestTest который реализует два метода:

  • OnRestServiceBuildDescription() объявляет новый scope или логическую группу и список собственных методов
  • test() логика
/local/php_interface/init.php<?php
class RestTest
{
    public static function OnRestServiceBuildDescription()
    {
        return array(
            'hmarketing' => array(
                'hmarketing.test' => array(
                    'callback' => array(__CLASS__, 'test'),
                    'options' => array(),
                ),
            )
        );
    }

    public static function test($query, $navStart, \CRestServer $server)
    {
        if ($query['error']) {
            throw new \Bitrix\Rest\RestException(
                'Message',
                'ERROR_CODE',
                \CRestServer::STATUS_PAYMENT_REQUIRED
            );
        }

        return array(
            'yourquery' => $query,
            'myresponse' => 'Мой собственный ответ'
        );
    }
}

AddEventHandler(
    'rest',
    'OnRestServiceBuildDescription',
    array(
        '\RestTest',
        'OnRestServiceBuildDescription'
    )
);

В результате появится новый scope под именем hmarketing, у которого будет метод hmarketing.test с обработчиком test() из класса RestTest:

Запрос будет выглядить следующим образом:

https://site1.loc/rest/1/78103bqeped92b8c/hmarketing.test

В метод test() можно запихнуть обсалютно любую логику.

Пример запроса в Postman с параметром:

Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!