Creating a custom API or extending the Core API
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:
- <config>
- <api>
- <resources>
- </resources>
- <acl>
- <resources>
- <all>
- </all>
- </resources>
- </acl>
- </api>
- </config>
We have to implement create, list, info, update and remove methods for customer resource. Lets add it to resources.
- <config>
- <api>
- ....
- <resources>
- <customer translate="title" module="customer">
- <title>Customer Resource</title>
- <methods>
- <list translate="title" module="customer">
- <title>Retrive customers</title>
- </list>
- <create translate="title" module="customer">
- <title>Create customer</title>
- </create>
- <info translate="title" module="customer">
- <title>Retrieve customer data</title>
- </info>
- <update translate="title" module="customer">
- <title>Update customer data</title>
- </update>
- <delete>
- <title>Delete customer</title>
- </delete>
- </methods>
- <faults module="customer">
- </faults>
- </customer>
- </resources>
- ....
- </api>
- </config>
Our resource will return some faults, let’s list them in the config:
- <config>
- <api>
- ....
- <resources>
- <customer translate="title" module="customer">
- ....
- <faults module="customer"> <!-- module="customer" specifies the module which will be used for translation. -->
- <data_invalid> <!-- if we get invalid input data for customers -->
- <code>100</ code> <!-- remove space -->
- <!-- we cannot know all the errors that can appear, their details can be found in error message for call -->
- <message>Invalid customer data. Details in error message.</message>
- </data_invalid>
- <filters_invalid>
- <code>101</ code> <!-- remove space -->
- <message>Invalid filters specified. Details in error message.</message>
- </filters_invalid>
- <not_exists>
- <code>102</ code> <!-- remove space -->
- <message>Customer doesn't exist.</message>
- </not_exists>
- <not_deleted>
- <code>103</ code> <!-- remove space -->
- <message>Customer was not deleted. Details in error message.</message>
- </not_deleted>
- </faults>
- </customer>
- </resources>
- ....
- </api>
- </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.
- <config>
- <api>
- ....
- <acl>
- <resources>
- <all>
- <customer translate="title" module="customer">
- <title>Customers</title>
- <list translate="title" module="customer">
- <title>View All</title>
- </list>
- <create translate="title" module="customer">
- <title>Create</title>
- </create>
- <info translate="title" module="customer">
- <title>Get Info</title>
- </info>
- <update translate="title" module="customer">
- <title>Update</title>
- </update>
- <delete translate="title" module="customer">
- <title>Delete</title>
- </delete>
- </customer>
- </all>
- </resources>
- </acl>
- </api>
- </config>
We also have to map ACL resources to API resource methods:
- <config>
- <api>
- <resources>
- <customer translate="title" module="customer">
- <title>Customer Resource</title>
- <acl>customer</acl>
- <methods>
- <list translate="title" module="customer">
- <title>Retrive customers</title>
- <acl>customer/list</acl>
- </list>
- <create translate="title" module="customer">
- <title>Create customer</title>
- <acl>customer/create</acl>
- </create>
- <info translate="title" module="customer">
- <title>Retrieve customer data</title>
- <acl>customer/info</acl>
- </info>
- <update translate="title" module="customer">
- <title>Update customer data</title>
- <acl>customer/update</acl>
- </update>
- <delete>
- <title>Delete customer</title>
- <acl>customer/delete</acl>
- </delete>
- </methods>
- ....
- </customer>
- </resources>
- ....
- </api>
- </config>
3. Creating API Resource Model |
Let’s create Mage_Customer_Model_Api that extends Mage_Api_Model_Resource_Abstract
- class Mage_Customer_Model_Api extends Mage_Api_Model_Resource_Abstract
- {
- public function create($customerData)
- {
- }
- public function info($customerId)
- {
- }
- public function items($filters)
- {
- }
- public function update($customerId, $customerData)
- {
- }
- public function delete($customerId)
- {
- }
- }
We cannot create method “list” because it’s a PHP keyword, so we will add the following to api.xml:
- <config>
- <api>
- <resources>
- <customer translate="title" module="customer">
- <model>customer/api</model> <!-- our model -->
- <title>Customer Resource</title>
- <acl>customer</acl>
- <methods>
- <list translate="title" module="customer">
- <title>Retrive customers</title>
- <method>items</method> <!-- we have another method name inside our resource -->
- <acl>customer/list</acl>
- </list>
- ....
- </methods>
- ....
- </resources>
- ....
- </api>
- </config>
And now will add some simple functionality to our resource model.
Create Customer:
- public function create($customerData)
- {
- try {
- $customer = Mage::getModel('customer/customer')
- ->setData($customerData)
- ->save();
- } catch (Mage_Core_Exception $e) {
- $this->_fault('data_invalid', $e->getMessage());
- // We cannot know all the possible exceptions,
- // so let's try to catch the ones that extend Mage_Core_Exception
- } catch (Exception $e) {
- $this->_fault('data_invalid', $e->getMessage());
- }
- return $customer->getId();
- }
Customer Info:
- public function info($customerId)
- {
- $customer = Mage::getModel('customer/customer')->load($customerId);
- if (!$customer->getId()) {
- $this->_fault('not_exists');
- // If customer not found.
- }
- return $customer->toArray();
- // We can use only simple PHP data types in webservices.
- }
Customers List with filtering.
- public function items($filters)
- {
- $collection = Mage::getModel('customer/customer')->getCollection()
- ->addAttributeToSelect('*');
- if (is_array($filters)) {
- try {
- foreach ($filters as $field => $value) {
- $collection->addFieldToFilter($field, $value);
- }
- } catch (Mage_Core_Exception $e) {
- $this->_fault('filters_invalid', $e->getMessage());
- // If we are adding filter on non-existent attribute
- }
- }
- $result = array();
- foreach ($collection as $customer) {
- $result[] = $customer->toArray();
- }
- return $result;
- }
Customer Update:
- public function update($customerId, $customerData)
- {
- $customer = Mage::getModel('customer/customer')->load($customerId);
- if (!$customer->getId()) {
- $this->_fault('not_exists');
- // No customer found
- }
- $customer->addData($customerData)->save();
- return true;
- }
Customer Delete:
- public function delete($customerId)
- {
- $customer = Mage::getModel('customer/customer')->load($customerId);
- if (!$customer->getId()) {
- $this->_fault('not_exists');
- // No customer found
- }
- try {
- $customer->delete();
- } catch (Mage_Core_Exception $e) {
- $this->_fault('not_deleted', $e->getMessage());
- // Some errors while deleting.
- }
- return true;
- }
Creating custom adapter for api |
In order to create custom webservice adapter we should implement Mage_Api_Model_Server_Adapter_Interface
- interface Mage_Api_Model_Server_Adapter_Interface
- {
- /**
- * Set handler class name for webservice
- *
- * @param string $handler
- * @return Mage_Api_Model_Server_Adapter_Interface
- */
- function setHandler($handler);
- /**
- * Retrive handler class name for webservice
- *
- * @return string
- */
- function getHandler();
- /**
- * Set webservice api controller
- *
- * @param Mage_Api_Controller_Action $controller
- * @return Mage_Api_Model_Server_Adapter_Interface
- */
- function setController(Mage_Api_Controller_Action $controller);
- /**
- * Retrive webservice api controller
- *
- * @return Mage_Api_Controller_Action
- */
- function getController();
- /**
- * Run webservice
- *
- * @return Mage_Api_Model_Server_Adapter_Interface
- */
- function run();
- /**
- * Dispatch webservice fault
- *
- * @param int $code
- * @param string $message
- */
- function fault($code, $message);
- } // Class Mage_Api_Model_Server_Adapter_Interface End
XmlRpc Adapter example:
- class Mage_Api_Model_Server_Adapter_Customxmlrpc
- extends Varien_Object
- implements Mage_Api_Model_Server_Adapter_Interface
- {
- /**
- * XmlRpc Server
- *
- * @var Zend_XmlRpc_Server
- */
- protected $_xmlRpc = null;
- /**
- * Set handler class name for webservice
- *
- * @param string $handler
- * @return Mage_Api_Model_Server_Adapter_Xmlrpc
- */
- public function setHandler($handler)
- {
- $this->setData('handler', $handler);
- return $this;
- }
- /**
- * Retrive handler class name for webservice
- *
- * @return string
- */
- public function getHandler()
- {
- return $this->getData('handler');
- }
- /**
- * Set webservice api controller
- *
- * @param Mage_Api_Controller_Action $controller
- * @return Mage_Api_Model_Server_Adapter_Xmlrpc
- */
- public function setController(Mage_Api_Controller_Action $controller)
- {
- $this->setData('controller', $controller);
- return $this;
- }
- /**
- * Retrive webservice api controller
- *
- * @return Mage_Api_Controller_Action
- */
- public function getController()
- {
- return $this->getData('controller');
- }
- /**
- * Run webservice
- *
- * @param Mage_Api_Controller_Action $controller
- * @return Mage_Api_Model_Server_Adapter_Xmlrpc
- */
- public function run()
- {
- $this->_xmlRpc = new Zend_XmlRpc_Server();
- $this->_xmlRpc->setClass($this->getHandler());
- $this->getController()->getResponse()
- ->setHeader('Content-Type', 'text/xml')
- ->setBody($this->_xmlRpc->handle());
- return $this;
- }
- /**
- * Dispatch webservice fault
- *
- * @param int $code
- * @param string $message
- */
- public function fault($code, $message)
- {
- throw new Zend_XmlRpc_Server_Exception($message, $code);
- }
- } // 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.
- public function run()
- {
- $this->_xmlRpc = new Zend_XmlRpc_Server();
- $this->_xmlRpc->setClass($this->getHandler());
- $this->getController()->getResponse()
- ->setHeader('Content-Type', 'text/xml')
- ->setBody($this->_xmlRpc->handle());
- return $this;
- }
Method “fault” allows us to send fault exceptions for XmlRpc service while handling request.
- public function fault($code, $message)
- {
- throw new Zend_XmlRpc_Server_Exception($message, $code);
- }
Common Error Messages |
Invalid api path In the <methods> node, you should list of methods available. These methods need to correspond directly to methods in api.php file.
For example in your api.xml file:
- <config>
- <api>
- <resources>
- <checkout_cart translate="title" module="checkout">
- <model>checkout/cart_api</model>
- <title>Cart API</title>
- <methods>
- <list translate="title" module="checkout">
- <title>Retrieve cart data</title>
- <method>info</method>
- </list>
- </methods>
- </checkout_cart>
- </resources>
- ...
- </api>
- </config>
Corresponds to the info method in your api.php file.
- class Mage_Cart_Model_Cart_Api extends Mage_Cart_Model_Api_Resource
- {
- public function info()
- {
- ...
- }
- }
If you are missing this method, the error “Invalid api path” will be returned.


