Extending the Magento web services API
08 Mar 2010, by Peter Spiller
4 Comments · Posted in Magento

    First of all, you need to find the Magento core file that provides the API method you want to extend. These are generally in model files called Api.php or under directories called Api. For example, I recently needed to look up customer orders by their IDs, as opposed to their increment IDs (aka their order numbers, such as '#100000003'). After some searching, I found the file that contains the relevant code at app/code/core/Mage/Sales/Model/Order/Api.php, in the _initOrder() method:

    
        protected function _initOrder($orderIncrementId)
        {
            $order = Mage::getModel('sales/order');
    
            /* @var $order Mage_Sales_Model_Order */
    
            $order->loadByIncrementId($orderIncrementId);
    
            if (!$order->getId()) {
                $this->_fault('not_exists');
            }
    
            return $order;
        }
    

    To override this, we could put a copy of the file in app/code/local, but that would mean copying the whole file and effectively overriding all the methods in it. Unfortunately this approach can be problematic when upgrading, since other modules may depend on new methods in the API model that aren't available due to the override. A better approach would be to only modify the function we are interested in. Create a file called Example_Webservices.xml in app/etc/modules, containing:

    <?xml version="1.0"?>
    <config>
        <modules>
            <Example_Webservices>
                <active>true</active>
                <codePool>local</codePool>
            </Example_Webservices>
        </modules>
    </config>
    

    Create the directory app/code/local/Example/Webservices/etc, and create a file called config.xml containing:

    <?xml version="1.0"?>
    <config>
        <global>
            <models>
                <sales>
                    <rewrite>
                        <order_api>Example_Webservices_Model_Sales_Order_Api</order_api>
                    </rewrite>
                </sales>
            </models>
        </global>
    </config>
    

    This is the usual code for overriding a model. We're rewriting all requests for the Mage_Sales_Model_Order_Api class to our own Example_Webservices_Model_Sales_Order_Api class.

    Finally, we need to actually create our model and override the method we're interested in. Create app/code/local/Example/Webservices/Model/Sales/Order/Api.php containing:

    
    class Example_Webservices_Model_Sales_Order_Api extends Mage_Sales_Model_Order_Api
    {
        protected function _initOrder($orderIncrementId)
        {
            $order = Mage::getModel('sales/order');
    
            if(is_string($orderIncrementId)) {
                $order->loadByIncrementId($orderIncrementId);
                if (!$order->getId()) {
                    $this->_fault('not_exists');
                }
            } else {
                $order->load($orderIncrementId);
                if (!$order->getId()) {
                    $this->_fault('not_exists');
                }
            }
            return $order;
        }
    }
    

    This class overrides the original model class we're overriding - this way, we only change the specific methods we want to change and minimise the chance of interfering with an upgrade. The modifications to the body of the method are quite simple. Instead of always loading by increment ID, we first check if the $orderIncrementId parameter we are passed is a string. If it's a string, we do an increment ID lookup; if not, we assume it's an ID and look up on that. This works in a similar way to products, where you can use the API to get a product by either ID or SKU.

    If your Magento store needs to work with another application in a way that Magento doesn't support, this simple example shows how easy it is to extend Magento's web services API's to allow you to achieve the integration that you require.

    Comments

    Peter, this is a great tutorial - in fact, all the Fontis tutorials are great ;)

    This approach works great when you're extending an existing API - but let's say that we want to create an API from scratch ...

    In our case we're building a custom extension to handle task management for different users inside Magento's Admin. We have API integration (sales orders, invoices, shipments) within our accounting system (Microsoft Dynamics NAV) already but we want to create a button in NAV to notify someone in Magento that there is a problem with an order by creating a task through a new API to our custom extension.

    I can't find documentation on creating a new API for our tasks extension - only on how to extend existing APIs. Can you give me any direction?

    Darren.
    Comment by Darren - 3 Apr 2010 3:52:41 AM
    Hi! This seems exactly what i have been looking for... But how can you call it? Can you call it like methods inside magento web service api? I mean would something like this work outside magento:

    [php]
    $mag_connection = new SoapClient( 'http://server/magento/api/soap/?wsdl' );
    $mag_session = $mag_connection->login( 'apiU', 'apiK' );
    $list = $mag_connection->call($mag_session, 'order.initOrder.);
    var_dump($list);
    [/php]
    Comment by Tommi - 11 Jun 2010 9:26:00 PM
    If you want to add method to API you have to define it in api.xml file. For example:

    [php]
    <config>
    <api>
    <resources>
    <sales_order translate="title" module="sales">
    <model>sales/order_api</model>
    <title>Order API</title>
    <acl>sales/order</acl>
    <methods>
    ...
    <create translate="title" module="sales">
    <title>Create order</title>
    <acl>sales/order/create</acl>
    </create>
    </methods>
    </sales_order>
    ...
    </resources>
    ...
    </api>
    </config>
    [/php]
    Comment by Jan Havrda - 1 Sep 2010 10:11:00 PM
    excellent post!! really helpful. better approach would be to only modify the function we are interested in
    Comment by rhizann2 - 9 Sep 2010 11:29:00 AM
    Comments are closed for this post