Tools
The decision to switch from a model based import to something else was easy and so we decided to give AvS_FastSimpleImport1 a try based on the fact that to the time of decision it was the best fit for our needs.
As mentioned above we also decided to give the RESTfull approach a try.
REST
At least when we started in the beginning of 2014 the amount of documentation and user generated content like blog posts was kinda low what made the journey not so super pleasant. In my naive mood I thought that it would be super easy because when there is an entity there will be a fully functional endpoint for this entity. That is not really the case. If you just plan on information retrieval, than you are somewhat fine, but if you try to manipulate or create data in the shop it gets tricky.
One of the main uses of an Api on the shop side is order handling and if you browse the Magento documentation for the REST-Api2 you often see “not implementedâ€. After a bit of investigation you can see that Mage_Sales_Model_Api2_Order_Rest_Admin_V1 is kinda empty. If you do not plan on core-hacking there has to be an alternative.
As mostly the best option is to get it done in a model of your own.
I just kept the naming and structure from the core files to allow easier adaptability because if you do massive changes you would have to mimic the whole authentication stuff to allow user and admin executable code and that would mean way more effort then i was willing to take. The whole configuration is done in the api2.xml file of the module:
<?xml version="1.0"?> <config> <api2> <resource_groups> <spl_interface translate="title" module="api2"> <title>SPL Interface API calls</title> <sort_order>30</sort_order> <children> <spl_interface_order translate="title" module="api2"> <title>Order</title> <sort_order>50</sort_order> </spl_interface_order> <spl_interface_product translate="title" module="api2"> <title>Product</title> <sort_order>60</sort_order> </spl_interface_product> </children> </spl_interface> </resource_groups> <resources> <spl_interfaceorders translate="title" module="api2"> <group>spl_interface_order</group> <model>spl_interface/sales_api2_order</model> <working_model>spl_interface/sales_api2_order</working_model> <title>Sales Order</title> <sort_order>10</sort_order> <privileges> <admin> <create>1</create> <retrieve>1</retrieve> <update>1</update> <delete>1</delete> </admin> </privileges> <routes> <route_entity> <route>/spl/orders/:id</route> <action_type>entity</action_type> </route_entity> <route_collection> <route>/spl/orders</route> <action_type>collection</action_type> </route_collection> </routes> <attributes module="api2"> <key>some key</key> <order_id>Order increment Id</order_id> <status>new status</status> <action>action to be taken</action> <track>tracking id</track> </attributes> <versions>1</versions> </spl_interfaceorders> </resources> </api2> </config>
As you can see i have choosen a different route /api/rest/spl/ for my adaptions to keep the original /api/rest clear and not too overpopulated with custom made stuff. I added the
route_entity
node only for convenience reasons because most of the times i handle collections and not single entities. Like in most cases an admin is allowed to do anything with the entitiy as defined in <privileges><admin>
. Authorization is handled by oauth. To explain the usage of oauth and magento would be too much for this but a really nice introduction that helped me a lot in the beginning was posted by Inchoo 3.
So you simply create the model Spl_Interface_Model_Sales_Api2_Order_Rest_Admin_V1 like this:
class Spl_Interface_Model_Sales_Api2_Order_Rest_Admin_V1 extends Mage_Sales_Model_Api2_Order_Rest { public function _retrieveCollection() { //get order Collection return $res; } public function _multiUpdate($data) { //do all the business logic magic in here. $this->_successMessage('OK', Mage_Api2_Model_Server::HTTP_OK, array('item' => $result)); if ($error) { $this->_errorMessage('Orders not found', Mage_Api2_Model_Server::HTTP_NOT_FOUND, array('item' => $error)); } } }
So in here i opted for using the _multiUpdate
method that is automagically called if you make a PUT-Request to the route_collection
endpoint. Other possible outcomes of calls are defined in the DocBlock of Mage_Api2_Model_Resource
. _successMessage
and _errorMessage
are response messages that can come alone or together, so if you have partial results you can also define some as success and others as errors.
For this case of order updates it was fast enough for me to use the standard Model based approach.
Fast Simple Import
Hopefully you have already used this imho wonderfull tool to easy up most of the import stuff you have to do.
We first used it to allow product import not only form the standard
.csv
files but from anything else. With the addition of nested array support it got even easier to use. Generally you can throw an array at the importer4 and it will do everything you formerly had to do yourself to use Mage_Import/Export
I added the following block to
resources
node:
<spl_interfaceproducts translate="title" module="api2"> <group>spl_interface_product</group> <model>spl_interface/catalog_api2_product</model> <working_model>spl_interface/catalog_api2_product</working_model> <title>Catalog Product</title> <sort_order>20</sort_order> <privileges> <admin> <create>1</create> <retrieve>1</retrieve> <update>1</update> <delete>1</delete> </admin> </privileges> <routes> <route_entity> <route>/spl/products/:id</route> <action_type>entity</action_type> </route_entity> <route_collection> <route>/spl/products</route> <action_type>collection</action_type> </route_collection> </routes> <attributes module="api2"> <key>some key</key> <Lieferstatus>Lieferstatus</Lieferstatus> <_type>Product Type</_type> <_attribute_set>Attribute Set</_attribute_set> <_category>Category</_category> <_links_related_sku>Zubehör</_links_related_sku> <_links_crosssell_sku>Cross selling</_links_crosssell_sku> <_super_products_sku>Child Products</_super_products_sku> <_super_attribute_code>Config Attribute</_super_attribute_code> <_super_attribute_option>Price Correction Option</_super_attribute_option> <_super_attribute_price_corr>addition to config base price</_super_attribute_price_corr> <qty>quantity</qty> <is_in_stock>iis</is_in_stock> <id>sku</id> <sku>sku</sku> </attributes> <versions>1</versions> </spl_interfaceproducts>
The normal product attribute nodes are allowed in the api but the more or less special ones starting with an underscore have to be listed if you do not want them to be filtered within the api. If you miss some attributes in the _multiUpdate($data) call it is the first thing you should consider adding them to the
<attributes>
node.
Conclusion
As you can see with this approach to not really extend the given REST api but to create completely new endpoints it is kinda easy to stand on the shoulders of the authentication system and still use all the magento given apis without getting in conflicts with rewrites or updates. You are even save from complications with other 3rd party extensions at least on the route/endpoint point of problems.
In the last few month we generated many new endpoints to allow 3rd party programs (still under our control data wise) to access information from within magento or to be able to adapt the magento admin backend in a form that would be kinda hard from within the admin area itself .
At least for me this is a very easy way to quickly add some features especially if you want to get or input some data from other applications. The old-school file exchanging gets a bit clumsy if you deal with multiple hosts or very frequent updates as csv is a big mess if you plan for incremental updates and xml has such an overhead data wise especially with simplexml as your weapon of choice in magento.