{"id":129,"date":"2010-09-13T23:47:52","date_gmt":"2010-09-13T22:47:52","guid":{"rendered":"https:\/\/greladesign.co\/blog\/?p=129"},"modified":"2011-08-29T11:53:06","modified_gmt":"2011-08-29T10:53:06","slug":"how-to-create-magentos-custom-api","status":"publish","type":"post","link":"https:\/\/greladesign.co\/blog\/2010\/09\/13\/how-to-create-magentos-custom-api\/","title":{"rendered":"How to create Magento&#8217;s Custom API?"},"content":{"rendered":"<p>It is not in-depth tutorial but description on how I tackled creation of custom API for magento. There are still vast fields of unknown but at least this will let you start building your own API and let you learn, like me, on how to do it. If I will find out anything new about it or I will gain some theoretical knowledge then I will update this post with those revelations.<br \/>\n<!--more--><br \/>\nEven the simplest example involves fairly few files and folders to be created, in this example we will create method which will return the version of the installed magento and list of best selling products, this is the structure of it:<\/p>\n<pre>\r\nmagento\/app\/\r\n        |- code\/community\/\r\n\t|           |- GrelaDesign\/\r\n\t|\t         |- Tutorial\/\r\n\t|                      |- etc\/\r\n\t|                           |- api.xml\r\n\t|                           |- config.xml\r\n        |                      |- Helper\/\r\n        |                           |- Data.php\r\n\t|                      |- Model\/\r\n\t|                           |- Core\/\r\n\t|                                 |- Api.php\r\n\t|                           |- DashBoard\/\r\n\t|                                 |- Api.php\r\n        |- etc\/modules\/\r\n\t            |- GrelaDesign_Tutorial.xml\r\n<\/pre>\n<p>general structure would look like:<\/p>\n<pre>\r\nmagento\/app\/code\/\r\n    |- community\/ or local\/ or core\/\r\n    |           |- COMPANYNAME\/\r\n    |             |- MODULENAME\/\r\n    |                      |- etc\/\r\n    |                           |- api.xml\r\n    |                           |- config.xml\r\n    |                      |- Helper\/\r\n    |                           |- Data.php\r\n    |                      |- Model\/\r\n    |                           |- OBJECT1\/\r\n    |                                 |- Api.php\r\n    |                           |- Object2\/\r\n    |                                 |- Api.php\r\n    |- etc\/modules\/\r\n                |- COMPANYNAME_MODULE.xml\r\n\r\n<\/pre>\n<p>Once you have created tutorial structure let&#8217;s start to fill it with content:<\/p>\n<p>This file instructs magento where to find our API<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;!-- GrelaDesign_Tutorial.xml --&gt;\r\n&lt;config&gt;\r\n\t&lt;modules&gt;\r\n\t\t&lt;GrelaDesign_Tutorial&gt;\r\n\t\t\t&lt;active&gt;true&lt;\/active&gt;\r\n\t\t\t&lt;codePool&gt;community&lt;\/codePool&gt;&lt;!-- this could be also 'local' --&gt;\r\n\t\t\t&lt;depends&gt;\r\n\t\t\t\t&lt;Mage_Api \/&gt;\r\n\t\t\t&lt;\/depends&gt;\r\n\t\t&lt;\/GrelaDesign_Tutorial&gt;\r\n\t&lt;\/modules&gt;\r\n&lt;\/config&gt;\r\n<\/pre>\n<p>config file, point to the model and helper, also to the translation files but I haven&#8217;t got this to work so far:), also in this revised version I have added a helper node as it seems to be quite important for Magento, without it I had an error thrown when I tried to access system->web services->roles and add\/edit role.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;!-- config.xml --&gt;\r\n&lt;config&gt;\r\n\t&lt;modules&gt;\r\n\t\t&lt;GrelaDesign_Tutorial&gt;&lt;!-- COMPANYNAME_MODULE --&gt;\r\n\t\t\t&lt;version&gt;0.0.0.1&lt;\/version&gt;\r\n\t\t&lt;\/GrelaDesign_Tutorial&gt;\r\n\t&lt;\/modules&gt;\r\n\t&lt;global&gt;\r\n\t\t&lt;models&gt;\r\n\t\t\t&lt;tutorial&gt;&lt;!-- MODULE, just first letter is lowercased, i.e. module CustomAPI would be placed here as customAPI --&gt;\r\n\t\t\t\t&lt;class&gt;GrelaDesign_Tutorial_Model&lt;\/class&gt;\r\n\t\t\t&lt;\/tutorial&gt;\r\n\t\t&lt;\/models&gt;\r\n\t\t&lt;helpers&gt;\r\n\t\t\t&lt;tutorial&gt;\r\n\t\t\t\t&lt;class&gt;GrelaDesign_Tutorial_Helper&lt;\/class&gt;\r\n\t\t\t&lt;\/tutorial&gt;\r\n\t\t&lt;\/helpers&gt;\r\n\t&lt;\/global&gt;\r\n&lt;\/config&gt;\r\n<\/pre>\n<p>In this tutorial we will create <del datetime=\"2010-09-18T21:47:41+00:00\">two<\/del> three methods for our API, I have deliberately placed them in different classes to show how it affects look of api.xml file. First will be getVersion in Core object, second will be getBestsellers in DashBoard object and third getTotals also in DashBoard object.<\/p>\n<p>The api.xml defines the resource name, by which programmer will call our exposed methods and will define Access Control Lists (ACL). The ACL is a way of grouping our methods into logical sets from which we will select (mix&#8217;n&#8217;match) when creating rules and webservices users. In our example we will have 2 sets of access groups: &#8220;allaccess&#8221; and &#8220;owneracess&#8221;. First will mark those methods that has no restrictions, and second marks the methods that only the &#8220;owner&#8221; user can access.<\/p>\n<p>&#8220;allaccess&#8221;<br \/>\n\t&#8211; getVersion<br \/>\n\t&#8211; getBestsellers<br \/>\n&#8220;owneraccess&#8221;<br \/>\n\t&#8211; getTotals<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;!-- api.xml --&gt;\r\n&lt;config&gt;\r\n\t&lt;api&gt;\r\n\t\t&lt;resources&gt;\r\n\t\t\t&lt;tutorial_core translate=&quot;title&quot; module=&quot;tutorial&quot;&gt;\r\n\t\t\t\t&lt;title&gt;GrelaDesign tutorial Core API calls&lt;\/title&gt;\r\n\t\t\t\t&lt;model&gt;tutorial\/core_api&lt;\/model&gt;\r\n\t\t\t\t&lt;acl&gt;greladesign\/tutorial&lt;\/acl&gt;\r\n\t\t\t\t&lt;methods&gt;\r\n\t\t\t\t\t&lt;getVersion translate=&quot;title&quot; module=&quot;tutorial&quot;&gt;\r\n\t\t\t\t\t\t&lt;title&gt;Returns version of this API&lt;\/title&gt;\r\n\t\t\t\t\t\t&lt;acl&gt;greladesign\/tutorial\/allaccess&lt;\/acl&gt;\r\n\t\t\t\t\t&lt;\/getVersion&gt;\r\n\t\t\t\t&lt;\/methods&gt;\r\n\t\t\t&lt;\/tutorial_core&gt;\r\n\t\t\t&lt;tutorial_dashboard translate=&quot;title&quot; module=&quot;tutorial&quot;&gt;\r\n\t\t\t\t&lt;title&gt;GrelaDesign tutorial DashBoard app API calls&lt;\/title&gt;\r\n\t\t\t\t&lt;model&gt;tutorial\/dashBoard_api&lt;\/model&gt;\r\n\t\t\t\t&lt;acl&gt;greladesign\/tutorial&lt;\/acl&gt;\r\n\t\t\t\t&lt;methods&gt;\r\n\t\t\t\t\t&lt;getSalesTotals translate=&quot;title&quot; module=&quot;tutorial&quot;&gt;\r\n\t\t\t\t\t\t&lt;title&gt;Get sales totals&lt;\/title&gt;\r\n\t\t\t\t\t\t&lt;method&gt;getTotals&lt;\/method&gt;&lt;!-- here we specify the method name if we have a conflict with built in method or we want to change the name i.e. because it is lengthy --&gt;\r\n\t\t\t\t\t\t&lt;acl&gt;greladesign\/tutorial\/owneraccess&lt;\/acl&gt;\r\n\t\t\t\t\t&lt;\/getSalesTotals&gt;\r\n\t\t\t\t\t&lt;getBestsellers translate=&quot;title&quot; module=&quot;tutorial&quot;&gt;\r\n\t\t\t\t\t\t&lt;title&gt;Get best selling product list&lt;\/title&gt;\r\n\t\t\t\t\t\t&lt;acl&gt;greladesign\/tutorial\/allaccess&lt;\/acl&gt;\r\n\t\t\t\t\t&lt;\/getBestsellers&gt;\r\n\t\t\t\t&lt;\/methods&gt;\r\n\t\t\t&lt;\/tutorial_dashboard&gt;\r\n\t\t&lt;\/resources&gt;\r\n\t\t&lt;resources_alias&gt;&lt;!-- here we can put aliases, shortened calls for our api resource, I haven't checked how alias behaves when it collides with different resource... --&gt;\r\n\t\t\t&lt;dashboard&gt;tutorial_dashboard&lt;\/dashboard&gt;\r\n\t\t\t&lt;core&gt;tutorial_core&lt;\/core&gt;\r\n\t\t&lt;\/resources_alias&gt;\r\n\t\t&lt;acl&gt;&lt;!-- Access Control List  to our resources, this tree structure is displayed in &quot;Resource Roles&quot; panel when you open role to edit --&gt;\r\n\t\t\t&lt;resources&gt;\r\n\t\t\t\t&lt;greladesign translate=&quot;title&quot; module=&quot;tutorial&quot;&gt;\r\n\t\t\t\t\t&lt;title&gt;GrelaDesign&lt;\/title&gt;\r\n\t\t\t\t\t&lt;sort_order&gt;100&lt;\/sort_order&gt;\r\n\t\t\t\t\t&lt;tutorial translate=&quot;title&quot; module=&quot;tutorial&quot;&gt;\r\n\t\t\t\t\t\t&lt;title&gt;Tutorial&lt;\/title&gt;\r\n\t\t\t\t\t\t&lt;sort_order&gt;100&lt;\/sort_order&gt;\r\n\t\t\t\t\t\t&lt;allaccess translate=&quot;title&quot; module=&quot;tutorial&quot;&gt;\r\n\t\t\t\t\t\t\t&lt;title&gt;Core functionality required by all users.&lt;\/title&gt;\r\n\t\t\t\t\t\t\t&lt;sort_order&gt;10&lt;\/sort_order&gt;\r\n\t\t\t\t\t\t&lt;\/allaccess&gt;\r\n\t\t\t\t\t\t&lt;owneraccess translate=&quot;title&quot; module=&quot;tutorial&quot;&gt;\r\n\t\t\t\t\t\t\t&lt;title&gt;Functions accessible only for owner.&lt;\/title&gt;\r\n\t\t\t\t\t\t\t&lt;sort_order&gt;50&lt;\/sort_order&gt;\r\n\t\t\t\t\t\t&lt;\/owneraccess&gt;\r\n\t\t\t\t\t&lt;\/tutorial&gt;\r\n\t\t\t\t&lt;\/greladesign&gt;\r\n\t\t\t&lt;\/resources&gt;\r\n\t\t&lt;\/acl&gt;\r\n\t&lt;\/api&gt;\r\n&lt;\/config&gt;\r\n<\/pre>\n<p>Re-assuming: config->api->resources lists api resources with the exposed methods, config->api->acl->resources defines access groups for our resources<\/p>\n<p>All we need to do now is just the API methods, lets start from the easiest:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;!-- magento\/app\/code\/community\/GrelaDesign\/Tutorial\/Model\/Core\/Api.php --&gt;\r\n&lt;?php\r\nclass GrelaDesign_Tutorial_Model_Core_Api\r\n{\r\n\t\/**\r\n\t * Returns version of the installed magento\r\n\t * @return String\r\n\t *\/\r\n\tpublic function getVersion()\r\n\t{\r\n\t\treturn Mage::getVersion();\r\n\t}\r\n}\r\n?&gt;\r\n<\/pre>\n<p>Simple isn&#8217;t it? Next will be more complex, but thanks to the snippi.net I was able to create it with no time, almost:)<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;!-- magento\/app\/code\/community\/GrelaDesign\/Tutorial\/Model\/DashBoard\/Api.php --&gt;\r\n&lt;?php\r\nclass GrelaDesign_Tutorial_Model_DashBoard_Api\r\n{\r\n\t\/**\r\n\t * Returns list of best selling products, returned list is limited to the number items specified in argument.\r\n\t * @param int $limit\r\n\t *\/\r\n\tpublic function getBestsellers($limit=5)\r\n\t{\r\n\t\t\/\/filter\r\n\t\t$visibility = array(\r\n\t\t\t\t\t  Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,\r\n\t\t\t\t\t  Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG\r\n\t\t\t\t  );\r\n\t\t\r\n\t\t$_arrayOfBestsellers = Mage::getResourceModel('reports\/product_collection')\r\n\t\t\t\t\t\t\t\t\t-&gt;addAttributeToSelect('*')\r\n\t\t\t\t\t\t\t\t\t-&gt;addOrderedQty()\r\n\t\t\t\t\t\t\t\t\t-&gt;addAttributeToFilter('visibility', $visibility)\r\n\t\t\t\t\t\t\t\t\t-&gt;setOrder('ordered_qty', 'desc')\r\n\t\t\t\t\t\t\t\t\t-&gt;getSelect()-&gt;limit($limit)-&gt;query();\r\n\t\t$bestProducts = array();\r\n\t\t\r\n\t\t$details = Mage::getModel('catalog\/product');\r\n\t\t\r\n\t\tforeach ($_arrayOfBestsellers as $product)\r\n\t\t{\r\n\t\t\t$details-&gt;load($product['entity_id']);\r\n\t\t\t$bestProduct[] = array(\r\n\t\t\t\t\t\t\t\t  &quot;qty&quot; =&gt; $product[&quot;ordered_qty&quot;]\r\n\t\t\t\t\t\t\t\t, &quot;price&quot; =&gt; $details-&gt;getPrice()\r\n\t\t\t\t\t\t\t\t, &quot;name&quot; =&gt; $details-&gt;getName()\r\n\t\t\t\t\t\t\t\t);\r\n\t\t}\r\n\t\t\r\n\t\treturn $bestProduct;\r\n\t}\r\n\t\/**\r\n\t * Get sales totals\r\n\t * Returns totals for : Revenue, Tax, Shipping and Quantity for given time range, default is last 24 hours.\r\n\t * @param String $period - default '24h', possible values are: 24h, ,1y, 2y\r\n\t *\/\r\n\tpublic function getTotals($period='24h')\r\n\t{\r\n\t\t\r\n        $collection = Mage::getResourceModel('reports\/order_collection')\r\n            -&gt;addCreateAtPeriodFilter($period)\r\n\t\t\t\/\/-&gt;getSelectCountSql()\r\n            -&gt;calculateTotals(1)\r\n\t\t\t;\r\n\t\t\/*\r\n\t\t$collection-&gt;addFieldToFilter('store_id',\r\n\t\t\tarray('eq' =&gt; Mage::app()-&gt;getStore(Mage_Core_Model_Store::ADMIN_CODE)-&gt;getId())\r\n\t\t);\r\n\t\t*\/\r\n        $collection-&gt;load();\r\n\t\t\r\n        $totals = $collection-&gt;getFirstItem();\r\n\t\t\r\n\t\t\r\n\t\treturn array(\r\n\t\t\t\t\t\t  'Revenue' =&gt; $totals-&gt;getRevenue()\r\n\t\t\t\t\t\t, 'Tax' =&gt; $totals-&gt;getTax()\r\n\t\t\t\t\t\t, 'Shipping' =&gt; $totals-&gt;getShipping()\r\n\t\t\t\t\t\t, 'Quantity' =&gt; $totals-&gt;getQuantity() * 1\r\n\t\t\t\t\t\t);\r\n\t}\r\n}\r\n?&gt;\r\n<\/pre>\n<p>Last bit is the helper class:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;!-- magento\/app\/code\/community\/GrelaDesign\/Tutorial\/Helper\/Data.php --&gt;\r\n&lt;?php\r\nclass GrelaDesign_Tutorial_Helper_Data extends Mage_Core_Helper_Abstract\r\n{\r\n\t\r\n}\r\n?&gt;\r\n<\/pre>\n<p>Ok that is all for this, lets test:<\/p>\n<p>log in to the magento admin area, and create 2 rules: &#8220;owner&#8221; and &#8220;client&#8221;, for first select all available resources (click on &#8220;greladesign&#8221;) for second we need to give only access to the essential methods (click on &#8220;Core functionality required by all users.&#8221;). When you have created those rules, create 2 users and assign those rules to them, i.e.<\/p>\n<p>rule: &#8220;owner&#8221;<br \/>\nuser: admin<br \/>\npass: 1admin<\/p>\n<p>rule: &#8220;client&#8221;<br \/>\nuser: johndoe<br \/>\npass: j0hn<\/p>\n<p>once this is done, create test.php file in the root of your magento folder and past the following:<br \/>\nthanks to <a href=\"http:\/\/snippi.net\">snippi.net<\/a> I can share with you this test file:)<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\n\/*\r\nCreate a file called, 'test.php' in the root of your Magento development environment.\r\nCopy the code below into your test.php file.\r\nBrowse to http:\/\/yourstore\/test.php.\r\n*\/\r\n\r\n\/\/ Tell this file to use the Mage libraries\r\n$mageFilename = 'app\/Mage.php';\r\nrequire_once $mageFilename;\r\numask(0);\r\n\r\n\/\/ Note we are using the 'app' directive not the 'run' directive here\r\n\/\/ Also note the store is named 'default' by, well, default.  But as Zeke pointed out if your store is\r\n\/\/ 'en' then you  would need to edit the following line to say Mage::app('en')\r\n\/\/ Let's go with 'default' for simplicity ...\r\nMage::app('default');\r\n\r\n\/\/ Your test code goes here\r\n\r\n\techo &quot;&lt;pre&gt;&quot;;\r\n\r\n$client = new Zend_XmlRpc_Client('http:\/\/127.0.0.1\/magento\/api\/xmlrpc\/');\r\n\r\n\/\/ If some stuff requires api authentication,\r\n\r\n\/\/ we should get session token\r\n\/\/login\t\r\n\t$session = $client-&gt;call('login', array('admin', '1admin'));\r\n\r\n\techo var_dump($client-&gt;call('call', array($session, 'tutorial_dashboard.getBestsellers'))), &quot;\\n&quot;;\r\n\techo var_dump($client-&gt;call('call', array($session, 'dashboard.getBestsellers'))), &quot;\\n&quot;;\r\n\techo var_dump($client-&gt;call('call', array($session, 'tutorial_dashboard.getSalesTotals'))), &quot;\\n&quot;;\r\n\techo var_dump($client-&gt;call('call', array($session, 'dashboard.getSalesTotals'))), &quot;\\n&quot;;\r\n\t\r\n\techo var_dump($client-&gt;call('call', array($session, 'tutorial_core.getVersion'))), &quot;\\n&quot;;\r\n\techo var_dump($client-&gt;call('call', array($session, 'core.getVersion'))), &quot;\\n&quot;;\r\n\/\/logout\r\n\techo $client-&gt;call('endSession', array($session)), &quot;\\n&quot;;\r\n\r\n\/\/login\t\r\n\t$session = $client-&gt;call('login', array('johndoe', 'j0hn'));\r\n\r\n\techo var_dump($client-&gt;call('call', array($session, 'tutorial_dashboard.getBestsellers'))), &quot;\\n&quot;;\r\n\techo var_dump($client-&gt;call('call', array($session, 'dashboard.getBestsellers'))), &quot;\\n&quot;;\r\n\ttry {\r\n\t\t\/\/this will throw an exception (&quot;access denied&quot;)\r\n\t\techo var_dump($client-&gt;call('call', array($session, 'tutorial_dashboard.getSalesTotals'))), &quot;\\n&quot;;\r\n\t\techo var_dump($client-&gt;call('call', array($session, 'dashboard.getSalesTotals'))), &quot;\\n&quot;;\r\n\t} catch (Exception $e) {\r\n\t\techo $e-&gt;getMessage(), &quot;\\n&quot;;\r\n\t}\r\n\t\r\n\techo var_dump($client-&gt;call('call', array($session, 'tutorial_core.getVersion'))), &quot;\\n&quot;;\r\n\techo var_dump($client-&gt;call('call', array($session, 'core.getVersion'))), &quot;\\n&quot;;\r\n\/\/logout\r\n\techo $client-&gt;call('endSession', array($session)), &quot;\\n&quot;;\r\n\r\n\techo &quot;&lt;\/pre&gt;&quot;;\r\n\r\n\r\n\r\n?&gt;\r\n<\/pre>\n<p>I hope you will find it useful in any way,<br \/>\nhappy coding<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It is not in-depth tutorial but description on how I tackled creation of custom API for magento. There are still vast fields of unknown but at least this will let you start building your own API and let you learn, &hellip; <a href=\"https:\/\/greladesign.co\/blog\/2010\/09\/13\/how-to-create-magentos-custom-api\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":""},"categories":[4,29,8],"tags":[28,13,5],"_links":{"self":[{"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/posts\/129"}],"collection":[{"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/comments?post=129"}],"version-history":[{"count":28,"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/posts\/129\/revisions"}],"predecessor-version":[{"id":149,"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/posts\/129\/revisions\/149"}],"wp:attachment":[{"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/media?parent=129"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/categories?post=129"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/greladesign.co\/blog\/wp-json\/wp\/v2\/tags?post=129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}