Extending the Magento API

Featured Image

If you are in the business of developing a mobile application or external web/desktop or some other application/service that needs to communicate with Magento trough its API, then my friend you are out of luck. I am not going to say Magento API is a trash, I’ll simply say it massively lacks certain methods within the existing exposed classes that will make your external application usable.

Its all about simple things, right? Well, here is one bottom line simple thing I would like to do with my Magento API. I would like to get a list of all available websites, stores and store views. Can I do that with the latest (as of this writing, 1.4.1.1) Magento? No I cannot! Can I get a list of … etc. For any serious scenario you will most likely be out of luck. What’s interesting is that rarely even a combination of several method calls will give you what you might need. Trust me on this one, I am writing Android application for Magento and its killing me.

So, how do we improve Magento API? That’s easy, I say lets override it enabling the further use all existing method calls while adding new methods to the same classes plus we can throw in some new classes to the API.

We will do so in the form of new extension, lets say that the extension name is “Ajzele_Mapy”.

First we will place the Ajzele_Mapy.xml file under the app/etc/modules/Ajzele_Mapy.xml with the content like shown below.

< ?xml version="1.0"?>
 
<config>
<modules>
<ajzele_mapy>
<active>false</active>
<codepool>community</codepool>
<depends>
<mage_api />
</depends>
</ajzele_mapy>
</modules>
</config>

Then we need to create appropriate file/directory structure inside the app/code/community/Ajzele/ folder.

First lets create the app/code/community/Ajzele/Mapy/etc/config.xml file with the content like shown below.

< ?xml version="1.0"?>
 
<config>
<modules>
<ajzele_mapy>
<version>1.0.0.0.0</version>
</ajzele_mapy>
</modules>
<global>
<models>
<customer>
<rewrite>
<customer_api>Ajzele_Mapy_Model_Customer_Customer_Api
</customer_api>
<group_api>Ajzele_Mapy_Model_Customer_Group_Api</group_api>
<address_api>Ajzele_Mapy_Model_Customer_Address_Api</address_api>
</rewrite>
</customer>
<directory>
<rewrite>
<country_api>Ajzele_Mapy_Model_Directory_Country_Api</country_api>
<region_api>Ajzele_Mapy_Model_Directory_Region_Api</region_api>
</rewrite>
</directory>
<catalog>
<rewrite>
<category_api>Ajzele_Mapy_Model_Catalog_Category_Api</category_api>
<product_api>Ajzele_Mapy_Model_Catalog_Product_Api</product_api>
<product_attribute_api>Ajzele_Mapy_Model_Catalog_Product_Attribute_Api
</product_attribute_api>
<product_attribute_media_api>Ajzele_Mapy_Model_Catalog_Product_Attribute_Media_Api
</product_attribute_media_api>
<product_attribute_set_api>Ajzele_Mapy_Model_Catalog_Product_Attribute_Set_Api
</product_attribute_set_api>
<product_attribute_tierprice_api>Ajzele_Mapy_Model_Catalog_Product_Attribute_Tierprice_Api
</product_attribute_tierprice_api>
<product_link_api>Ajzele_Mapy_Model_Catalog_Product_Link_Api
</product_link_api>
<product_type_api>Ajzele_Mapy_Model_Catalog_Product_Type_Api
</product_type_api>
</rewrite>
</catalog>
<cataloginventory>
<rewrite>
<stock_item_api>Ajzele_Mapy_Model_CatalogInventory_Stock_Item_Api
</stock_item_api>
</rewrite>
</cataloginventory>
<directory>
<rewrite>
<country_api>Ajzele_Mapy_Model_Directory_Country_Api</country_api>
<region_api>Ajzele_Mapy_Model_Directory_Region_Api</region_api>
</rewrite>
</directory>
<sales>
<rewrite>
<order_api>Ajzele_Mapy_Model_Sales_Order_Api</order_api>
<order_invoice_api>Ajzele_Mapy_Model_Sales_Order_Invoice_Api
</order_invoice_api>
<order_shipment_api>Ajzele_Mapy_Model_Sales_Order_Shipment_Api
</order_shipment_api>
</rewrite>
</sales>
</models>
</global>
</config>

In the above app/code/community/Ajzele/Mapy/etc/config.xml file you will notice I overridden all (if I did not miss any) of the exposed Magento API classes. For example, definition Ajzele_Mapy_Model_Directory_Country_Api tells the Magento to use Ajzele_Mapy_Model_Directory_Country_Api each time it wishes to use the Mage_Directory_Model_Country_Api class which is exposed to the API.

My appropriate Ajzele_Mapy_Model_Directory_Country_Api class would then have a content like shown below.

< ?php
 
class Ajzele_Mapy_Model_Directory_Country_Api extends Mage_Directory_Model_Country_Api
{
 
}
[/sourcecode]
 
This example merely overrides the Mage_Directory_Model_Country_Api class, not doing anything more at the moment. Now if I would like to add new public method (one that does not exist in the Mage_Directory_Model_Country_Api), then I would (with one extra configuration entry shown below) call that method trough API like "directory_country.myNewMethod".
 
In order to do so, I would need to add one more config info to another file called app/code/community/Ajzele/Mapy/etc/api.xml.
 
[sourcecode='xml']
<?xml version="1.0"?>
 
<config>
<api>
<resources>
<customer translate="title" module="customer">
<model>customer/customer_api</model>
<title>Customer Api</title>
<acl>customer</acl>
<methods>
<!-- Mapy methods here... -->
</methods>
</customer>
<customer_group>
<model>customer/group_api</model>
<title>Customer's Groups Api</title>
<acl>customer</acl>
<methods>
<!-- Mapy methods here... -->
</methods>
</customer_group>
<customer_address>
<model>customer/address_api</model>
<title>Customer Address Api</title>
<acl>customer/address</acl>
<methods>
<!-- Mapy methods here... -->
</methods>
</customer_address>
<directory_country translate="title" module="directory">
<model>directory/country_api</model>
<title>Country Api</title>
<acl>directory/country</acl>
<methods>
<!-- Mapy methods here... -->
</methods>
</directory_country>
<directory_region translate="title" module="directory">
<model>directory/region_api</model>
<title>Region Api</title>
<acl>directory/region</acl>
<methods>
<!-- Mapy methods here... -->
</methods>
</directory_region>
<catalog_category translate="title" module="catalog">
<model>catalog/category_api</model>
<title>Category API</title>
<acl>catalog/category</acl>
<methods></methods>
</catalog_category>
 
<catalog_category_attribute translate="title" module="catalog">
<title>Category attributes API</title>
<model>catalog/category_attribute_api</model>
<acl>catalog/category</acl>
<methods></methods>
</catalog_category_attribute>
 
<catalog_product translate="title" module="catalog">
<title>Product API</title>
<model>catalog/product_api</model>
<acl>catalog/product</acl>
<methods></methods>
</catalog_product>
 
<catalog_product_attribute translate="title" module="catalog">
<title>Product attributes API</title>
<model>catalog/product_attribute_api</model>
<acl>catalog/product</acl>
<methods></methods>
</catalog_product_attribute>
 
<catalog_product_attribute_set translate="title" module="catalog">
<title>Product attribute sets API</title>
<model>catalog/product_attribute_set_api</model>
<acl>catalog/product</acl>
<methods></methods>
</catalog_product_attribute_set>
 
<catalog_product_type translate="title" module="catalog">
<title>Product types API</title>
<model>catalog/product_type_api</model>
<acl>catalog/product</acl>
<methods></methods>
</catalog_product_type>
 
<catalog_product_attribute_media translate="title" module="catalog">
<title>Product Images API</title>
<model>catalog/product_attribute_media_api</model>
<acl>catalog/product/media</acl>
<methods></methods>
</catalog_product_attribute_media>
 
<catalog_product_attribute_tier_price translate="title" module="catalog">
<title>Product Tier Price API</title>
<model>catalog/product_attribute_tierprice_api</model>
<acl>catalog/product</acl>
<methods></methods>
</catalog_product_attribute_tier_price>
 
<catalog_product_link translate="title" module="catalog">
<title>Product links API (related, cross sells, up sells)</title>
<model>catalog/product_link_api</model>
<acl>catalog/product/link</acl>
<methods></methods>
</catalog_product_link>
</resources>
<acl>
<resources>
<customer translate="title" module="customer">
<title>Customers</title>
<sort_order>3</sort_order>
 
<!-- Mapy method acl's here... -->
</customer>
<directory translate="title" module="directory">
<title>Directory</title>
<sort_order>5</sort_order>
 
<!-- Mapy method acl's here... -->
</directory>
<catalog translate="title" module="catalog">
<title>Catalog</title>
<sort_order>1</sort_order>
</catalog>
</resources>
</acl>
</api>
</config>

Careful study of the above file shows how Magento exposes its class and methods to the API. For example, is you open the app\code\core\Mage\Directory\etc\api.xml file you will see how it exposes methods for the Directory module.

So, in short, my module merely overrides all the available/exposed API classes enabling you to add new methods or overwrite existing ones in the API. Entire code provided above does not contain any custom methods or does it overwrite any. Its merely an “empty” and “ready” project for writing your own stuff.

I have taken this “extending the Magento API” concept very serious as I will most likely need it for my future Android – Magento apps. With that in mind I have created a repository on the http://github.com/ajzele/mapy (which is empty for now, planning on submitting my first code in a week or so). As you guessed it, the project name is Mapy, short from Magento + API + y to spice up the things :).

Hope this article was helpful for you.

Cheers.


24 comments

  1. How to get Size and image Url by using Array of catalogProductRequestAttributes (optional) in catalogProductInfo (SOAP V2) API in Android .

    Please provide some information regarding this API .
    Thanks

  2. Got a question:
    I’d like to add a generic API to allow SMS sending to multiple customers.
    Assuming i have the code ready and the method is called “sendSMStoManyPeople(array of mobile numbers)”
    Where do i need to add this in the api structure (since it’s not customer/catalog specific) and how will i call it from the API ?
    thanks
    S

  3. Hi men, im trying to make a WSDL, to do this i start to found the methods that bring me the info from DB, then i make an array to return all the request info


    $product_data[‘Id’]=$product->getId();
    $product_data[‘Ref’]=$product->getSku();
    $product_data[‘Weight’]=$product->getData(‘weight’);

    return $product_data;

    if i print the request info “print_r( $product_data);”, the info is the necesary but now, i dont know where i have to put the code to create the wsdl …

    Thank`s.

  4. Hi..
    I am having a very big problem here. I am using Magento API to create an order.. but now how can I use Paypal to pay using

    $resultPaymentMethod = $client->call(‘call’, array($session,’cart_payment.method’,array($cartid,$paymentMethod)));

    I would really appreciate if somebody can point me to the right direction 🙁

  5. And, I’m a fool. I had a typo in etc/modules/Ajzele_Mapy.xml

    With that fixed, all is well.

  6. This looks incredible useful.
    Thanks.

    I’m attempting to add a new api call, but I’m not having any success. Does this seem like the right procedure?

    I’m trying to add a new api call for adding options to a Dropdown attribute.

    I create a function addoption in Ajzele/Mapy/Model/Catalog/Product/Attribute/Api.php

    then I add the following block to Ajzele/Mapy/etc/api.xml:

    <addoption translate="title" module="catalog">
        <title>Add attribute options</title>
        <acl>catalog/product/attribute/addoption</acl>
    </addoption>

    and that goes between:

    <catalog_product_attribute translate="title" module="catalog">
        <title>Product attributes API</title>
        <model>catalog/product_attribute_api</model>
            <acl>catalog/product</acl>
            <methods>
                ...
            </methods>

    but when I make the api call:

    $client->call($session, 'catalog_product_attribute.addoption');

    I get the SoapFault: “Invalid api path”

    I’m sure I must be missing something simple.
    I’ve cleared caches, and it’s no better.
    Any ideas?

    -Thanks again

  7. Can anyone provide an small example how to implement a REST adapter and fire a call? would be amazing…

  8. @Bob Brodie
    Implementation of REST in Magento is very easy, because API uses mapping of methods through the configuration. You just need to implement REST adapter. You can find a small tutorial here:
    http://www.magentocommerce.com/wiki/doc/webservices-api/custom-api#creating_custom_adapter_for_api

    @Branko Ajzele
    I am agree with Alan, there is no difference in creation of your own api resource and overriding existent one, just 2 additional lines in api.xml. I prefer to define my own resource, if it is for my custom functionality. Also it allows me to install another extension that extends core API (for example: adds additional method to customer API resource) without any modifications to my module. It saves my time a lot 🙂

  9. Cool stuff Branko, and hey, if you need an alpha/beta tester for your Android app, I’d be happy to try it on my HTC Desire :).

  10. @Alan Thanks for the tip/heads up. Think I’ll stick “mapy” to front of the method calls for existing classes, so call could look like “customer_address.mapyFindLatestFromState”. Basically I would like people to make an easy transition to using “Mapy” and built in Magento API. I know it sound like a lot of bs* … most of all I would like to write as less as little possible of new code :), thus override of existing and adding of new functionality.

  11. That makes sense. The core API seems to be one of the less Zend Framework-y aspects of Magento programming. Zend_Soap_Server wasn’t introduced until ZF 1.6; maybe that’s why they went the route they did?

  12. Useful information, although you’d be better off creating a new top level namespace in the API and adding all your methods to it. If the method name you choose is the same as the method name a future version of the API chooses there’s a slight chance of a collision with this setup.

  13. @Jonathan Can it get any slower than the current one? LOL… just kidding. Well, I would say the same. Basically I am just rewriting their stuff with mine, so it should all come down to Magento’s mechanism that checks the config for rewrites?! Also, please keep in mind that I still haven’t committed any code to the github repo, so no real stuff to test for now. Will do so in a few days.

  14. That sounds really cool – I’m envisioning a lot of possibilities with a REST API, especially with integrations to Rails webapps. I’ll keep an eye on Mapy.

  15. @Bob

    I must admit I did not study the “Server/Client” implementation of the API mechanism for now. I would say this is something I will investigate and possibly implement in later stages of my Mapy project (if I stick to it long enough). Although I would say it should not be that difficult 🙂

  16. Great article! How difficult do you think it would be to create a REST API for Magento? Zend Framework supports it but I’ve never seen Zend_Soap_Server in Magento so it may be something that would have to be started from scratch. I’ve read your article about creating your own API, but how about reproducing the official API in REST?

    Thanks,
    Bob Brodie

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.