Magento step by step: REST API

  • Tutorial
In a previous article, we looked at creating a "skeleton" for exporting orders. In the same, consider the creation of the same skeleton, but import through the REST API.

From Wiki: REST (short for Representational State Transfer - “Representative State Transfer”) - in a more commonly used narrow sense, REST is understood as a method of interaction between components of a distributed application on the Internet, in which a remote procedure call is a regular HTTP request ( usually GET or POST; such a request is called a REST request), and the necessary data is passed as request parameters. This method is an alternative to more complex methods such as SOAP, CORBA, and RPC.


According to the standard htaccess Magento, all requests submitted to / api / should be sent to api.php:
RewriteRule ^api/([a-z][0-9a-z_]+)/?$ api.php?type=$1 [QSA,L] 


Why should you use the standard API? Besides the fact that everything is ready for it, API requests are always launched in administrator mode (Mage :: app () -> getStore () -> isAdmin () === true), which implies language independence for EAV attributes , and the absence of any events from the frontend area.
The configuration file api2.xml is responsible for the REST configuration in the etc directory of the module, the api2 node .

So, let's try to expand the previous functionality with import as well.
Suppose the input data format from an external system is as follows:
145000003uiwq12889124211145000003ZZZuiwq128zzz89124211


In the indicated request, one order will be real, the second - no.

app / code / local / Easy / Interfacing / etc / api2.xml
Easy Interfacing REST30Orders50easy_interfacingeasy_interfacing/api2_ordereasy_interfacing/api2_order_filterOrders101/easy_interfacing/ordercollection1Order IDShipment data


The resource_groups node is responsible for the ACL in System> Web Services> REST Roles . In the REST API resources themselves, we specify the easy_interfacing membership group and api2_order model, which will be responsible for the functionality.
The path to the interface is indicated in route_collection, we also indicate that processing will be carried out on a plurality of elements (action_type = route_collection). In our REST API, we will do everything on guest access, so as not to suffer from passwords at the training stage: in the code, the difference will only be in the class name.
Node attributesresponsible for the ACL filter of the imported data (Mage_Api2_Model_Acl_Filter). You can also force attributes to the array of imported data by adding a list to the forced_attributes node. All possible options can be found in api2.xml of any module that allows you to import / export data, for example, Mage_Sales or Mage_Catalog.

By default, all attributes should not be arrays, which does not fit our format (shipment is an array), so let's create our own filter, where we fix this problem in the Mage_Api2_Model_Acl_Filter :: collectionIn method:

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];
    } 
}

Do not forget to set ACL accesses in System> Web services> REST - Roles :

and in System> Web services> REST - Attributes :


Finally, create the API class itself:
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;
    }
}

We don’t really need anything in it, only _addResult and a couple of error code constants. We also create a REST class inherited from this:
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());
            }
        }
    }
}

In it, we redefine the dispatch method to replace the filter with ours and change the rendering a bit, since by default Magento will give a little crooked response based on the collection of messages from getResponse ().
Since we specified action_type = collection, we implement the _multiUpdate method. $ FilteredData will always contain an already filtered array (if you remove the ID from the ACL attributes, then Easy_Interfacing_Model_Order :: import will throw an exception, or even crash).

Add the import method to our Easy_Interfacing_Model_Order:
app / code / local / Easy / Interfacing / Model / Order.php
class Easy_Interfacing_Model_Order
{
    public function import(Mage_Sales_Model_Order $order, array $data)
    {
        Mage::throwException('Not implemented');
    }
    public function export(Mage_Sales_Model_Order $order)
    {
        Mage::throwException('Not implemented');
    }
}


You also need to create an API guest class, as it will be called upon guest access to REST.
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 
{
}


Ultimately, if you did everything correctly, when you request to http: /// api / rest / easy_interfacing / order / using the PUT method through any REST client of the input data specified above, an answer of the form:
500145000003Not implemented40414501100003

Also popular now: