Программный интерфейс (REST API)

Обзор

  • следует модели RESTfull;
  • авторизация Basic HTTP (логин — электронная почта; пароль — ключ доступа к программному интерфейсу (API Key) из профиля пользователя);
  • вложенность объектов не более 2х (products/features, products/options, products/features/images);
  • привилегии групп пользователей, а также привязка к ним определяется в самих объектах.

Что такое REST

REpresentational State Transfer (REST) — передача представлений состояний. Стиль построения архитектуры распределенного приложения. Был описан и популяризован в 2000 году Роем Филдингом (Roy Fielding), одним из создателей протокола HTTP.

Суть реализации программного интерфейса (RESTful API) — это представление логики работы магазина в виде набора объектов(сущностей) с изменяемым состоянием. Средство реализации — протокол HTTP 1.1, его методы, статусы, заголовки.

Для изменения состояния объекта используется 4 метода:

  • GET — Получение информации об объекте
  • POST — Создание нового объекта
  • PUT — Обновление информации об объекте
  • DELETE — Удаление объекта

Исходя из того, что REST-архитектура подразумевает работу с логикой в виде работы с состоянием объектов, объекты программного интерфейса (API) не всегда будут соответствовать объектам модели, используемым в магазине.

Наглядный пример — реализация добавления товаров в корзину. Для этого в концепции REST следует создать новый объект /cart, и PUT-запрос на этот объект с указанием в параметрах идентификатора (id) товара и будет как раз добавлением товара в корзину. При этом как такового не существует объекта “корзина” в модели магазина.

Работа с программным интерфейсом (API)

В качесте адреса во всех примерах используется example.com. Следует заменять на адрес вашего магазина.

Авторизация

Для авторизации используется механизм Basic HTTP.

В качестве имени пользователя выступает адрес электронной почты, в качестве пароля — ключ доступа к программному интерфейсу (API), который задаётся в профиле пользоваеля в Панели администратора магазина.

Примечание

В случе передачи электронной почты в строке URL следует знак @, заменить на %40.

Тестирование c помощью клиентов для работы с программным интерфейсом (REST) (cURL)

cURL позволяет выполнять любые HTTP методы для нужного ресурса. Можно передавать любые параметры запросов и заголовков, а также проверять ответные заголовки и данные. Инструмент коммандной строки «curl», стандартен для большинства *nix систем. Для пользователей Windows подойдёт MinGW/MSYS.

Примечание

Можно использовать другие клиенты для работы с программным интерфейсом (REST), например, Postman для Google Chrome.

Пример использования и базовые опции

curl -X PUT www.example.com/api/entity/1 -d "some=var" -d "other=var2" -H "Accept: text/json" -I
  • -X [METHOD] определяет HTTP метод.
  • -d "name=value" устанавливает имя и значения переменных в POST/PUT.
  • -H [HEADER] устанавливает заголовок.
  • -I отображает заголовки ответа.

Передача в строке URL:

curl --basic -X GET 'http://admin%40example.com:va1t900b3P2UCQWDHZk1MKB83963z16i@example.com/api/users/'

Использование параметра --user:

curl --user admin@example.com:va1t900b3P2UCQWDHZk1MKB83963z16i  -X GET 'http://example.com/api/users/'

Через заголовок --header:

curl --header 'Authorization: Basic YWRtaW5AZXhhbXBsZS5jb206dmExdDkwMGIzUDJVQ1FXREhaazFNS0I4Mzk2M3oxNmk=' -X GET 'http://example.com/api/users/'

В заголовке пара логина/пароля должна быть зашифрована по base64. Следующие строки демонстрируют процесс кодирования:

$token = base64_encode("yourApiUserName:yourAPIToken");
$authHeaderString = 'Authorization: Basic ' . $token;

Формат выходных данных

Нужно установить заголовок Accept. По умолчанию даные возвращаются в JSON:

curl --header "Accept: application/json"

Формат входных данных

Нужно установить заголовок Content-type. По умолчанию ожидаются в text/plain:

curl --header "Content-type: application/json"

Архитектура

Процесс обработки запроса на примере GET

Точка входа

Файл api.php — точка входа в программный интерфейс (REST API).

URL для обращения к API:

http://example.com/api.php?_d=products http://example.com/api.php?_d=products/1

При включенном mod_rewrite:

http://example.com/api/products http://example.com/api/products/1

Правило преобразования срабатывает только тогда, когда в пути сразу есть /api.

Форматы ввода/вывода

Форматы отвечают за преобразование данных из строки запроса в массив и наоборот из массива в строку ответа.

Определяется это заголовками HTTP-запроса.

  • ContentType — формат, в котором пришли данные;
  • Accept — формат, в котором данные нужно вернуть.

За преобразования отвечает класс Api\FormatManager. Он является синглтоном, при инициализации ему нужно передать классы обработчиков, которые доступны. Каждый обработчик формата должен реализовать интерфейс Api\IFormat. Два метода в нём отвечают за преобразование данных, а getMimeTypes в виде массива возвращает список MIME типов которые может обработать этот класс.

Доступные форматы:

  • Api\Formats\Json — JSON;
  • Api\Formats\Text — простой текст (Plain Text).

Объекты REST

Ключевая единица модели REST — это объекты, в нашем случае будем называть их сущности. Для работы с ними используется классы унаследованные от абстрактного Api\AEntity.

Каждая сущность должна обязательно реализовывать 4 базовых метода соотвествеющих HTTP.

  • Для получения списка обектов, либо одного, если указан $id, параметры для фильтрации придут в $params:

    abstract public function index($id = '', $params = array());
    
  • Для создания объекта. Свойства объекта придут в $params. В случае пустого массива свойств, либо наличия идентификатора объекта в адресе, запрос автоматически будет сформирован со статусом STATUS_METHOD_NOT_ALLOWED и отправлен до вызова этого метода.

    В случае успеха метод должен возвращать статус STATUS_CREATED:

    abstract public function create($params);
    
  • Для обновления объекта. Свойства объекта придут в $params. Идентификатор в $id. В случае пустого массива свойств, либо пустого идентификатора объекта в адресе, запрос автоматически будет сформирован со статусом STATUS_METHOD_NOT_ALLOWED и отправлен до вызова этого метода:

    abstract public function update($id, $params);
    
  • Для удаления объекта. Идентификатор придёт в $id. В случае пустого идентификатора объекта в адресе, запрос автоматически будет сформирован со статусом STATUS_METHOD_NOT_ALLOWED и отправлен до вызова этого метода.

    В случае успеха метод должен возвращать статус STATUS_NO_CONTENT:

    abstract public function delete($id);
    

Привилегии

Используются привилегии, которые назначаются группам пользователей, в которых в свою очередь состоит тот пользователь, который обращается к программному интерфейсу (API).

Привязка к привилегиям осуществляется посредством указания в классе сущности соответствия названий привилегий методам класса. На примере Api\Entities\Users:

public function privileges()
{
    return array(
        'create' => 'manage_users',
        'update' => 'manage_users',
        'delete' => 'manage_users',
        'index'  => 'view_users'
    );
}

Создание, обновление и удаление — это manage_users, просмотр — view_users.

Вложенные сущности

Примечание

Пример вложенной сущности — Categories/Products.

Связи “многие ко многим” быть не может. Это ограничение введено специально для исключения путаницы. В большинстве случаев структура объектов магазина устроена так, что один объект будет более зависим от другого. Например, в случае с категориями и товарами это категории, потому что они являются “контейнером” для товаров.

Связь реализуется таким образом. В родителя добавляется функция возвращающая названия её дочерних сущностей:

public function childEntities()
{
    return array(
        'products'
    );
}

После этого все запросы вида /родитель/:id_родителя/потомок, обрабатываются так (на примере categories/3/products):

  • извлекаются оба объекта из пути, id родителя обязателен;
  • создаётся объект родителя;
  • вызывается метод родителя index с параметром id для получения данных о родительской сущности;
  • если статус, возвращённый методом index родителя 200 (STATUS_OK), то данные передаются в потомка и вызывается соответствующий HTTP метод потомка. В нём уже доступны данные о родителе, в качестве возвращаемого значения будет результат его работы;
  • если статус, возвращённый методом index родителя не 200, то будет возвращён результат его работы.