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>
- <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>
- </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 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:
- <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.


