Организация API + REST

Краткая информация

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

Установить модуль можно отсюда - отсюда

Базовая установка модуля описана - здесь

Структура файлов

После установки модуля через систему обновления в демо режиме или , купив, используя купон, необходимо добавить папку api в корне сайта, можно назвать иначе и изменить соответствующие настройки инициализации.

/ - корень сайта
/api/ - директория для обработчиков
/api/index.php  -централизованный обработчик, который обрабатывает все методы
/api/.htaccess - файл для предотвращения просмотра всей иерархии 
/api/sale/ - группа методов для работы с магазином, например sale.abb2Basket, sale.setQuantity  и тп.
/api/sale/add2_basket.php - обработчик метода sale.add2Basket
/api/sale/set_quantity.php - обработчик метода sale.setQuantity
/api/.. - и так далее, любые какие захотите группы и методы

Инициализация модуля

Допустим что вы решили разместить свое API по адресу /api/ относительно корня ( соответственно директория в корне сайта - /api/). В этой папке необходимо создать индексный файл - index.php с вызовом модуля.

<? 

define('STOP_STATISTICS', true);
define('NO_KEEP_STATISTIC', 'Y');
define('NO_AGENT_STATISTIC', 'Y');
define('DisableEventsCheck', true);
define('BX_SECURITY_SHOW_MESSAGE', true);
define('NOT_CHECK_PERMISSIONS', true);

require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_before.php'); 

if(\Bitrix\Main\Loader::includeModule('bxmaker.api'))
{
    $oApi = \Bxmaker\Api\Handler::getInstance();
   /* если директория не /api/, а например /ajax/, 
      необходимо указать директорию явно, так -
      $oApi->setCurDir(dirname(__FILE__)); */ 
    $oApi->setParam(array(
        'IBLOCK_ID_CATALOG' => 2,
    ));
    $oApi->init();
    $oApi->showResult();
}
else
{
      echo json_encode(array('ststus' => 0, 'error' => array(
        'error_code' => 0,
        'error_msg' => 'Модуль обработки запросов не установлен'
    )));
}

После этого создать файл .htaccess со следующим текстом

Options -Indexes

Добавлении обработчиков для методов

После этого можно добавлять уже обработчики для методов запроса. Например нам нужен метод, для добавления товара в корзину. логично его вывести в группу sale.

Таким образом чтобы указывать в запросе значение для параметра method = sale.add2Basket, необходимо создать папку sale и файл add2_basket.php.

Если в методе присутствует точка, то это будет означать наличие группы запросов, соответственно для группы запросов отводится отдельная дирректория относительна корня обработчика запросов.

К примеру:

  • method = sale.basket.add, путь до файла будет таким - /api/sale/basket/add.php
  • method = user.login, путь до файла - /api/user/login.php
  • и так далее.

Если в значении метода присутствуют большие буквы, то они будут заменены на символ "_" и прописной аналог, например:

  • method = user.loginByPhone, путь до файла - /api/user/login_by_phone.php
  • method = sale.basket.setQuantity, путь до файла - /api/sale/basket/set_quantity.php

В таком случае необходимо добавить обработчик этого метода, файл должен находиться по этому пути /api/sale/add2_basket.php и иметь примерно следующий код:

<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) { 
    die();
}


if (!$this->get('product_id') || intval($this->get('product_id')) <= 0) {
    $this->setError('Не удалось определить идентификатор товара!', '1');

    return false;
}

$quantity = max(1, intval($this->get('quantity')));


CModule::IncludeModule('iblock');
CModule::IncludeModule('catalog');
CModule::IncludeModule('sale');

$arFields = array();

$dbr = CIBlockElement::GetList(array(), array(
    'IBLOCK_ID' => $this->getParam('IBLOCK_ID_CATALOG'), //здесь мы используем параметр указаны при инициализации модуля
    'ID' => intval($this->get('product_id'))
), false, array('nPageSize' => 1), array('*'));

if ($ob = $dbr->GetNextElement()) {
    $arFields = $ob->GetFields();
    $arFields['PROPERTIES'] = $ob->GetProperties();

    Add2BasketByProductID($arFields['ID'], $quantity);

   // тут можно еще посчитать количество товаров в корзине и их стоимость

    $this->setResult(array(
        'msg' => 'Товар успешно добавлен в корзину',
        'basket' => array(),
        'quantity' => $quantity,
        'price' => $price,
        'price_format' => number_format($price, 0, '.', ' ')
    ));

}
else {
    $this->setError('Не удалось найти товар');
    return false;
}

Запросы к API с клиентской стороны

После этого можно например используя jQuery делать AJAX запросы вида:

$.ajax({ 
   url: '/api/',
    type: 'POST',
    dataType: 'json',
    data: {
        sessid: BX.bitrix_sessid(),
        method: 'sale.add2Basket',
        product_id: btn.attr('data-product-id'),
        quantity: (isNaN(q) ? 1 : q)
    },
    error: function (r) {
        btn.removeClass('preloader');
    },
    success: function (r) {
        
        if (!!r.response) {
            btn.text('В корзине');

            $(document).trigger('changeBasket', r.response.basket);
            
        }
        else if (!!r.error) {
            console.log('error', r.error.error_msg);           
        }
    }
});

Запросы в JSON формате

Модуль обрабатывает помимо обычных POST запросов с перечислением параметров и их значений, еще и вариант отправки JSON строки, когда данные уже закодированы и имеют кодировку UTF-8.

Пример запросов к серверу в этом формате


$oHttp = new \Bitrix\Main\Web\HttpClient();
    $oHttp->setHeader('Content-Type', 'application/json; charset=utf-8');

    // идентификатор сессии можно передать в заголовке запроса
    $oHttp->setHeader('X-Csrf-Token', 'значение идентификтаора сессии');


    
    $arParams = array(
        'method' => 'user.state',
        'sessid' => 'значение идентификтаора сессии', // в теле зарпоса или в заголовке
    );
    $result = $oHttp->post('http://localhost/api/', json_encode($arParams));
    
    echo '<pre>';
    print_r($result);
    echo '</pre>';

// на примере axios, для jQuery, fetch -  подобно, пример в инете можно найти
 axios({
            url : '/api/',
            method: 'POST',
            headers: {
                'Content-Type': 'application/json;charset=utf-8'
            },
            data: JSON.stringify({
                method: 'lk.auth.checkCode',
                sessid: 'sessid',
                phone: '79991112233',
                code: '1111'
            })
        }).then(result => { console.log('result', result)});


Формат ответов от API

В результате работы модуля будет возвращен ответ, который в случае успешного результат вернет объект response , иначе error в формате JSON.

Для обычного ответа

/* в случае успешного выполнения операции */
{
    "response" : {
       "msg" : "Товар успешно добавлен в корзину"
   }
}

Для ответа с ошибкой

{
    "error": {
        "msg": "Ваша сессия закончилась, обновите страницу и попробуйте снова.",
        "code": "/api/1",
        "more": []
     }     
}