REST API

Что такое 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-ключ, который задаётся в профиле пользоваеля в Панели администратора магазина.

Примечание

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

Тестирование c помощью REST-клиентов (cURL)

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

Примечание

Можно использовать другие REST-клиенты, например, REST Console или Advanced REST Client для Gooogle 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"

Архитектура

Диаграмма классов

The diagram of CS-Cart & Multi-Vendor REST API classes.

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

Processing a GET request.

Точка входа

Файл 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);
    
  • Для обновления объекта. Cвойства объекта придут в $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, то будет возращён результат его работы.