Creating a custom API or extending the Core API

Last modified by meral_m on Mon, July 12, 2010 00:54
Source|Old Revisions  

This is an old revision of the document!


Create your own API

... api for customer module, that operates with basic customer info (firstname, lastname, email ...).

1. Describe API Resource in api.xml

Create api.xml in customer module /etc folder with this contents:

  1. <config>
  2.     <api>
  3.         <resources>
  4.         </resources>
  5.         <acl>
  6.             <resources>
  7.                 <all>
  8.                 </all>
  9.             </resources>
  10.         </acl>
  11.     </api>
  12. </config>

We have to implement create, list, info, update and remove methods for customer resource. Lets add it to resources.

  1. <config>
  2.     <api>
  3. ....
  4.         <resources>
  5.             <customer translate="title" module="customer">
  6.                 <title>Customer Resource</title>
  7.                 <methods>
  8.                     <list translate="title" module="customer">
  9.                         <title>Retrive customers</title>                       
  10.                     </list>
  11.                     <create translate="title" module="customer">
  12.                         <title>Create customer</title>
  13.                     </create>
  14.                     <info translate="title" module="customer">
  15.                         <title>Retrieve customer data</title>
  16.                     </info>
  17.                     <update translate="title" module="customer">
  18.                         <title>Update customer data</title>
  19.                     </update>
  20.                     <delete>
  21.                         <title>Delete customer</title>
  22.                     </delete>
  23.                 </methods>
  24.                 <faults module="customer">                   
  25.                 </faults>
  26.             </customer>
  27.         </resources>
  28. ....
  29.     </api>
  30. </config>

Our resource will return some faults, let’s list them in the config:

  1. <config>
  2.     <api>
  3. ....
  4.         <resources>
  5.             <customer translate="title" module="customer">
  6. ....
  7.                 <faults module="customer"> <!-- module="customer" specifies the module which will be used for translation. -->
  8.                     <data_invalid> <!-- if we get invalid input data for customers -->
  9.                         <code>100</ code> <!-- remove space -->
  10.                         <!-- we cannot know all the errors that can appear, their details can be found in error message for call -->
  11.                         <message>Invalid customer data. Details in error message.</message>
  12.                     </data_invalid>
  13.                     <filters_invalid>
  14.                         <code>101</ code> <!-- remove space -->
  15.                         <message>Invalid filters specified. Details in error message.</message>
  16.                     </filters_invalid>
  17.                     <not_exists>
  18.                         <code>102</ code> <!-- remove space -->
  19.                         <message>Customer doesn't exist.</message>
  20.                     </not_exists>
  21.                     <not_deleted>
  22.                         <code>103</ code> <!-- remove space -->
  23.                         <message>Customer was not deleted. Details in error message.</message>
  24.                     </not_deleted>
  25.                 </faults>
  26.             </customer>
  27.         </resources>
  28. ....
  29.     </api>
  30. </config>

2. Describe ACL For API Resource

In order to prevent unathorized access to our custom API we have to define the ACL resources that can be restricted.

  1. <config>
  2.     <api>
  3. ....
  4.         <acl>
  5.             <resources>
  6.                     <customer translate="title" module="customer">
  7.                          <title>Customers</title>
  8.                          <list translate="title" module="customer">
  9.                             <title>View All</title>
  10.                          </list>
  11.                          <create translate="title" module="customer">
  12.                             <title>Create</title>
  13.                          </create>                         
  14.                          <info translate="title" module="customer">
  15.                             <title>Get Info</title>
  16.                          </info>
  17.                          <update translate="title" module="customer">
  18.                             <title>Update</title>
  19.                          </update> 
  20.                          <delete translate="title" module="customer">
  21.                             <title>Delete</title>
  22.                          </delete>                       
  23.                     </customer>
  24.             </resources>
  25.         </acl>
  26.     </api>
  27. </config>

We also have to map ACL resources to API resource methods:

  1. <config>
  2.     <api>
  3.         <resources>
  4.             <customer translate="title" module="customer">
  5.                 <title>Customer Resource</title>
  6.                 <acl>customer</acl>
  7.                 <methods>
  8.                     <list translate="title" module="customer">
  9.                         <title>Retrive customers</title>
  10.                         <acl>customer/list</acl>
  11.                     </list>
  12.                     <create translate="title" module="customer">
  13.                         <title>Create customer</title>
  14.                         <acl>customer/create</acl>
  15.                     </create>
  16.                     <info translate="title" module="customer">
  17.                         <title>Retrieve customer data</title>
  18.                         <acl>customer/info</acl>
  19.                     </info>
  20.                     <update translate="title" module="customer">
  21.                         <title>Update customer data</title>
  22.                         <acl>customer/update</acl>
  23.                     </update>
  24.                     <delete>
  25.                         <title>Delete customer</title>
  26.                         <acl>customer/delete</acl>
  27.                     </delete>
  28.                 </methods>
  29.               ....
  30.             </customer>
  31.         </resources>
  32. ....
  33.     </api>
  34. </config>

3. Creating API Resource Model

Let’s create Mage_Customer_Model_Api that extends Mage_Api_Model_Resource_Abstract

  1. class Mage_Customer_Model_Api extends Mage_Api_Model_Resource_Abstract
  2. {
  3.    
  4.     public function create($customerData)
  5.     {
  6.    
  7.     }
  8.  
  9.     public function info($customerId)
  10.     {
  11.    
  12.     }
  13.  
  14.     public function items($filters)
  15.     {
  16.    
  17.     }
  18.  
  19.     public function update($customerId, $customerData)
  20.     {
  21.     }
  22.  
  23.     public function delete($customerId)
  24.     {
  25.     }
  26. }

We cannot create method “list” because it’s a PHP keyword, so we will add the following to api.xml:

  1. <config>
  2.     <api>
  3.         <resources>
  4.             <customer translate="title" module="customer">
  5.                 <model>customer/api</model> <!-- our model -->
  6.                 <title>Customer Resource</title>
  7.                 <acl>customer</acl>
  8.                 <methods>
  9.                     <list translate="title" module="customer">
  10.                         <title>Retrive customers</title>
  11.                         <method>items</method> <!-- we have another method name inside our resource -->
  12.                         <acl>customer/list</acl>
  13.                     </list>
  14. ....                   
  15.                 </methods>
  16. ....
  17.         </resources>
  18. ....
  19.     </api>
  20. </config>

And now will add some simple functionality to our resource model.

Create Customer:

  1.     public function create($customerData)
  2.     {
  3.         try {
  4.             $customer = Mage::getModel('customer/customer')
  5.                 ->setData($customerData)
  6.                 ->save();
  7.         } catch (Mage_Core_Exception $e) {
  8.             $this->_fault('data_invalid', $e->getMessage());
  9.             // We cannot know all the possible exceptions,
  10.             // so let's try to catch the ones that extend Mage_Core_Exception
  11.         } catch (Exception $e) {
  12.             $this->_fault('data_invalid', $e->getMessage());
  13.         }
  14.         return $customer->getId();
  15.     }

Customer Info:

  1.     public function info($customerId)
  2.     {
  3.         $customer = Mage::getModel('customer/customer')->load($customerId);
  4.         if (!$customer->getId()) {
  5.             $this->_fault('not_exists');
  6.             // If customer not found.
  7.         }
  8.         return $customer->toArray();
  9.         // We can use only simple PHP data types in webservices.
  10.     }

Customers List with filtering.

  1.     public function items($filters)
  2.     {
  3.         $collection = Mage::getModel('customer/customer')->getCollection()
  4.             ->addAttributeToSelect('*');
  5.  
  6.         if (is_array($filters)) {
  7.             try {
  8.                 foreach ($filters as $field => $value) {
  9.                     $collection->addFieldToFilter($field, $value);
  10.                 }
  11.             } catch (Mage_Core_Exception $e) {
  12.                 $this->_fault('filters_invalid', $e->getMessage());
  13.                 // If we are adding filter on non-existent attribute
  14.             }
  15.         }
  16.  
  17.         $result = array();
  18.         foreach ($collection as $customer) {
  19.             $result[] = $customer->toArray();
  20.         }
  21.  
  22.         return $result;
  23.     }

Customer Update:

  1.     public function update($customerId, $customerData)
  2.     {
  3.         $customer = Mage::getModel('customer/customer')->load($customerId);
  4.  
  5.         if (!$customer->getId()) {
  6.             $this->_fault('not_exists');
  7.             // No customer found
  8.         }
  9.  
  10.         $customer->addData($customerData)->save();
  11.         return true;
  12.     }

Customer Delete:

  1.     public function delete($customerId)
  2.     {
  3.         $customer = Mage::getModel('customer/customer')->load($customerId);
  4.  
  5.         if (!$customer->getId()) {
  6.             $this->_fault('not_exists');
  7.             // No customer found
  8.         }
  9.  
  10.         try {
  11.             $customer->delete();
  12.         } catch (Mage_Core_Exception $e) {
  13.             $this->_fault('not_deleted', $e->getMessage());
  14.             // Some errors while deleting.
  15.         }
  16.  
  17.         return true;
  18.     }

Creating custom adapter for api

In order to create custom webservice adapter we should implement Mage_Api_Model_Server_Adapter_Interface

  1. interface Mage_Api_Model_Server_Adapter_Interface
  2. {
  3.     /**
  4.      * Set handler class name for webservice
  5.      *
  6.      * @param string $handler
  7.      * @return Mage_Api_Model_Server_Adapter_Interface
  8.      */
  9.     function setHandler($handler);
  10.  
  11.     /**
  12.      * Retrive handler class name for webservice
  13.      *
  14.      * @return string
  15.      */
  16.     function getHandler();
  17.  
  18.     /**
  19.      * Set webservice api controller
  20.      *
  21.      * @param Mage_Api_Controller_Action $controller
  22.      * @return Mage_Api_Model_Server_Adapter_Interface
  23.      */
  24.     function setController(Mage_Api_Controller_Action $controller);
  25.  
  26.     /**
  27.      * Retrive webservice api controller
  28.      *
  29.      * @return Mage_Api_Controller_Action
  30.      */
  31.     function getController();
  32.  
  33.     /**
  34.      * Run webservice
  35.      *
  36.      * @return Mage_Api_Model_Server_Adapter_Interface
  37.      */
  38.     function run();
  39.  
  40.     /**
  41.      * Dispatch webservice fault
  42.      *
  43.      * @param int $code
  44.      * @param string $message
  45.      */
  46.     function fault($code, $message);
  47.  
  48. } // Class Mage_Api_Model_Server_Adapter_Interface End

XmlRpc Adapter example:

  1. class Mage_Api_Model_Server_Adapter_Customxmlrpc
  2.     extends Varien_Object
  3.     implements Mage_Api_Model_Server_Adapter_Interface
  4. {
  5.      /**
  6.       * XmlRpc Server
  7.       *
  8.       * @var Zend_XmlRpc_Server
  9.       */
  10.      protected $_xmlRpc = null;
  11.  
  12.      /**
  13.      * Set handler class name for webservice
  14.      *
  15.      * @param string $handler
  16.      * @return Mage_Api_Model_Server_Adapter_Xmlrpc
  17.      */
  18.     public function setHandler($handler)
  19.     {
  20.         $this->setData('handler', $handler);
  21.         return $this;
  22.     }
  23.  
  24.     /**
  25.      * Retrive handler class name for webservice
  26.      *
  27.      * @return string
  28.      */
  29.     public function getHandler()
  30.     {
  31.         return $this->getData('handler');
  32.     }
  33.  
  34.      /**
  35.      * Set webservice api controller
  36.      *
  37.      * @param Mage_Api_Controller_Action $controller
  38.      * @return Mage_Api_Model_Server_Adapter_Xmlrpc
  39.      */
  40.     public function setController(Mage_Api_Controller_Action $controller)
  41.     {
  42.          $this->setData('controller', $controller);
  43.          return $this;
  44.     }
  45.  
  46.     /**
  47.      * Retrive webservice api controller
  48.      *
  49.      * @return Mage_Api_Controller_Action
  50.      */
  51.     public function getController()
  52.     {
  53.         return $this->getData('controller');
  54.     }
  55.  
  56.     /**
  57.      * Run webservice
  58.      *
  59.      * @param Mage_Api_Controller_Action $controller
  60.      * @return Mage_Api_Model_Server_Adapter_Xmlrpc
  61.      */
  62.     public function run()
  63.     {
  64.         $this->_xmlRpc = new Zend_XmlRpc_Server();
  65.         $this->_xmlRpc->setClass($this->getHandler());
  66.         $this->getController()->getResponse()
  67.             ->setHeader('Content-Type', 'text/xml')
  68.             ->setBody($this->_xmlRpc->handle());
  69.         return $this;
  70.     }
  71.  
  72.     /**
  73.      * Dispatch webservice fault
  74.      *
  75.      * @param int $code
  76.      * @param string $message
  77.      */
  78.     public function fault($code, $message)
  79.     {
  80.         throw new Zend_XmlRpc_Server_Exception($message, $code);
  81.     }
  82. } // Class Mage_Api_Model_Server_Adapter_Customxmlrpc End

“setHandler”, “getHandler”, “setController” and “getController” methods have simple implementation that uses Varien_Object getData/setData methods.

“run” an “fault” have native implementation for XmlRpc webservice.

Method “run” defines webservice logic in this adapter for creating XmlRpc server to handle XmlRpc requests.

  1.     public function run()
  2.     {
  3.         $this->_xmlRpc = new Zend_XmlRpc_Server();
  4.         $this->_xmlRpc->setClass($this->getHandler());
  5.         $this->getController()->getResponse()
  6.             ->setHeader('Content-Type', 'text/xml')
  7.             ->setBody($this->_xmlRpc->handle());
  8.         return $this;
  9.     }

Method “fault” allows us to send fault exceptions for XmlRpc service while handling request.

  1.     public function fault($code, $message)
  2.     {
  3.         // basic example
  4.         throw new Zend_XmlRpc_Server_Exception($message, $code);
  5.     }

Common Error Messages

Invalid api path

In the <methods> node, you should list all of the methods you wish to have available in your API. The methods you list need to correspond directly to methods found in your api.php file.

For example in your api.xml file:

  1. <config>
  2.     <api>
  3.         <resources>
  4.             <checkout_cart translate="title" module="checkout">
  5.                 <model>checkout/cart_api</model>
  6.                 <title>Cart API</title>
  7.                 <methods>
  8.                     <list translate="title" module="checkout">
  9.                         <title>Retrieve cart data</title>
  10.                         <method>info</method>       
  11.                     </list>
  12.                 </methods>
  13.             </checkout_cart>                 
  14.         </resources>
  15.     ...         
  16.     </api>
  17. </config>

Corresponds to the info method in your api.php file.

  1. class Mage_Checkout_Model_Cart_Api extends Mage_Cart_Model_Api_Resource
  2. {
  3. public function info()
  4. {
  5. ...
  6. }
  7. }

If you are missing this method, the error “Invalid api path” will be returned.




 

Magento 2 GitHub Repository

Magento Job Board - Some sort of tag line goes here

Latest Posts| View all Jobs