Magento шаг за шагом: REST API

В предыдущей статье мы рассмотрели создание «скелета» для экспорта заказов. В этой же рассмотриим создание такого же скелета, но импорта через REST API.С Вики: REST (сокр. от англ. Representational State Transfer — «передача репрезентативного состояния») — в более употребительном узком смысле под REST понимается метод взаимодействия компонентов распределённого приложения в сети Интернет, при котором вызов удаленной процедуры представляет собой обычный HTTP-запрос (обычно GET или POST; такой запрос называют REST-запрос), а необходимые данные передаются в качестве параметров запроса. Этот способ является альтернативой более сложным методам, таким как SOAP, CORBA и RPC.

По стандартному htaccess Magento, все запросы поданные на /api/ должны отправляться на api.php:

RewriteRule ^api/([a-z][0–9a-z_]+)/?$ api.php? type=$1 [QSA, L] Почему нужно стоить использовать именно стандартный API? Помимо того, что для него уже все готово, API-запросы всегда запускаются в режиме администратора (Mage: app ()→getStore ()→isAdmin () === true), что подразумевает как языковую независимость для EAV-аттрибутов, так и отсутствие каких-либо событий из области frontend.За конфигурацию REST отвечает конфигурационный файл api2.xml в директории etc модуля, нода api2.

Итак, попробуем расширить предыдущий функционал еще и импортом.Допустим, формат вводных данных с внешней системы будет таков:

145000003 uiwq12889124 21 1 145000003ZZZ uiwq128zzz89124 21 1 В указанном запросе один заказ будет реальным, второй — нет.

app/code/local/Easy/Interfacing/etc/api2.xml

Easy Interfacing REST 30 Orders 50 easy_interfacing easy_interfacing/api2_order easy_interfacing/api2_order_filter Orders 10 1 /easy_interfacing/order collection 1 Order ID Shipment data Нода resource_groups отвечает за ACL в System > Web Services > REST Roles. В самих же ресурсах REST API мы указываем группу принадлежности easy_interfacing и модель api2_order, которая будет отвечать за функционал.Путь к интерфейсу укаазн в route_collection, мы также указываем, что обработка будет вестись на множественном количестве элементов (action_type = route_collection). В нашем REST API мы все будем делать на гостевом доступе, чтоб не мучаться с паролями на этапе обучения: в коде разница будет только в названии класса.Нода attributes отвечает за ACL фильтр импортируемых данных (Mage_Api2_Model_Acl_Filter). Так же можно форсировать аттрибуты в массив импортируемых данных добавлением списка в ноду forced_attributes. Все возможные варианты можно найти в api2.xml любого модуля, позволяющего делать импорт/экспорт данных, например, Mage_Sales или Mage_Catalog.

По умолчанию все аттрибуты не должны быть массивами, что не подходит под наш формат (shipment — массив), поэтому создадим собственный фильтр, где исправим эту проблему в методе Mage_Api2_Model_Acl_Filter: collectionIn:

app/code/local/Easy/Interfacing/Model/Api2/Order/Filter.php

class Easy_Interfacing_Model_Api2_Order_Filter extends Mage_Api2_Model_Acl_Filter { public function collectionIn ($items) { $nodeName = key ($items); if (! is_numeric (key ($items[$nodeName]))) { $items[$nodeName] = array ($items[$nodeName]); } if (is_array ($items[$nodeName])) { foreach ($items[$nodeName] as &$item) { $item = $this→in ($item); } } return $items[$nodeName]; } } Не забудьте проставить ACL доступы в System > Web services > REST — Roles: ec3ac009876c4b3b9bc266b0026b244b.pngи в System > Web services > REST — Attributes: 84ec047148ae4af287e63d02577e5e0c.pngИ, наконец создадим сам класс API: app/code/local/Easy/Interfacing/Model/Api2/Order.php

class Easy_Interfacing_Model_Api2_Order extends Mage_Api2_Model_Resource { const RESULT_ERROR_NOT_FOUND = 404; const RESULT_ERROR_IMPORT = 500; const RESULT_SUCCESS = 200; protected $_responseItems = array (); protected function _addResult (array $item, $errorCode, $errorMessage) { $result = array ('result' => $errorCode, 'id' => $item['id']); if ($errorMessage) { $result['error'] = $errorMessage; } $this→_responseItems[] = $result; } } В нем нам особо ничего не нужно, только _addResult и пара констант кодов ошибок. Так же создадим REST-класс, унаследованный от этого: app/code/local/Easy/Interfacing/Model/Api2/Order/Rest.php class Easy_Interfacing_Model_Api2_Order_Rest extends Easy_Interfacing_Model_Api2_Order { public function dispatch () { $this→_filter = Mage: getModel ('easy_interfacing/api2_order_filter', $this); parent: dispatch (); $this→_render ($this→_responseItems); }

protected function _multiUpdate (array $filteredData) { foreach ($filteredData as $item) { $order = Mage: getModel ('sales/order')→loadByIncrementId ($item['id']); /* @var $order Mage_Sales_Model_Order */ if (!$order→getId ()) { $this→_addResult ($item, self: RESULT_ERROR_NOT_FOUND); continue; } try { Mage: getSingleton ('easy_interfacing/order')→import ($order, $item); $this→_addResult ($item, self: RESULT_SUCCESS); } catch (Exception $ex) { $order→addStatusHistoryComment ('Failed importing order: ' . $ex→getMessage ())→save (); $this→_addResult ($item, self: RESULT_ERROR_IMPORT, $ex→getMessage ()); } } } } В нем переопределим метод dispatch, чтобы подменить фильтр на наш и сменить немного рендеринг, так как по умолчанию Magento выдаст немного кривой ответ, основанный на коллекции сообщений из getResponse ().Так как мы указывали action_type=collection, мы реализуем метод _multiUpdate. В $filteredData всегда будет находиться уже отфильтрованный массив (если из ACL аттрибутов убрать ID, то Easy_Interfacing_Model_Order: import бросит исключение, или даже крэшнется).app/code/local/Easy/Interfacing/Model/Api2/Order/Rest/Guest/V1.php class Easy_Interfacing_Model_Api2_Order_Rest_Guest_V1 extends Easy_Interfacing_Model_Api2_Order_Rest { } Guest-класс API так же нужно создать, т.к. именно он будет вызван при гостевом доступе к REST.В конечном итоге, если Вы все сделали правильно, при запросе на http:///api/rest/easy_interfacing/order/ методом PUT через любой REST-клиент вводных данных указанных выше, придет ответ вида: 500 145000003 Not implemented 404 14501100003

© Habrahabr.ru