22
Oct
Writing a Magento Custom API call
I've been doing some work with the open source Magento web store software, mostly to do with their XMLRPC API for our ReadyToShip software. Inevitably, the requirement arised that couldn't be solved by the existing Magento API calls, so it was time to take a look at writing some code and building my own custom api call (as suggested by the Magento documentation).
Unfortunately, the documentation on doing so is kind of sketchy, so it was a slightly frustrating experience, not least because of the complexity of Magento's data structures. I've got a 'Hello World' API call working now though, and this post will have a dual purpose: to help others who have been wrestling with the same problem, and to actually get it straight what I did to get it working!
Before I start, can I just say that Mage::Log is your friend! I figured out a lot of what is going on here by throwing Mage::Log("Bla bla") throughout the existing Magento code.
OK, first steps, here is the directory structure of my custom files:
magento/
|-- app/
|-- code/
| |-- local/
| |-- CompanyName/
| |-- ModuleName/
| |-- etc/
| | |-- api.xml
| | |-- config.xml
| |-- Model/
| |-- ObjectModel/
| |-- Api.php
|-- modules/
|-- etc/
|-- CompanyName_ModuleName.xml
A lot of directories for only 4 new files! But the directory structure is important, as Magento makes use of strict naming conventions to find where it's class and config files are.
OK, let's tell Magento that we're writing a new module, and in doing so, where to find it. Here are the contents of magento/app/etc/modules/CompanyName_ModuleName.xml :
<?xml version="1.0"?> <config> <modules> <CompanyName_ModuleName> <active>true</active> <codePool>local</codePool> </CompanyName_ModuleName> </modules> </config>
Pretty simple, huh? From this piece of XML, Magento knows to look in the magento/app/code/local/CompanyName/ModuleName directory for your module.
Next, let's take a look at the config file for our module. Here are the contents of magento/app/code/local/CompanyName/ModuleName/etc/config.xml:
<?xml version="1.0" encoding="UTF-8"?> <config> <modules> <CompanyName_ModuleName> <version>0.1.0</version> </CompanyName_ModuleName> </modules> <global> <models> <test> <class>CompanyName_ModuleName_Model</class> </test> </models> </global> </config>
In this file we're defining an extra variable for our module (I suspect the <modules> section could go in the CompanyName_ModuleName.xml file, actually, as all the XML config is merged together), as well as telling Magento the base class name for the module (this is important to those constantly having Magento look under the Mage/ directory for your class files instead of your company name, a problem I struggled with for quite a while).
Next is the definition of our API call, here are the contents of magento/app/code/local/CompanyName/ModuleName/etc/api.xml:
<?xml version="1.0"?> <config> <api> <resources> <resource_name translate="title" module="companyname_modulename"> <title>Title Of My Resource</title> <model>modulename/objectmodel_api</model> <methods> <methodName translate="title" module="companyname_modulename"> <title>Title Of My Method</title> </methodName> </methods> </resource_name> </resources> </api> </config>
I'm still a bit fuzzy on exactly how this section works, but what I do know is that the <model> variable is what tells Magento where your class is. I think the resource name can be whatever you like, and I'm not sure where the module attribute is used as I seem to be able to set it to anything I like and it still works.
Finally, let's look at the API method itself, here are the contents of magento/app/code/local/CompanyName/ModuleName/Model/ObjectModel/Api.php:
<?php class CompanyName_ModuleName_Model_ObjectModel_Api extends Mage_Api_Model_Resource_Abstract { public function methodName($arg) { return "Hello World, here is my argument: " . $arg; } } ?>
And there you have it! You can call your method using resource_name.methodName like you would any other API call.
Note: if you have Magento caching turned on, you will need to refresh the cache under System -> Cache Management before the changes to your model will take effect. This caught me out a few times as changes I'd made were not being reflected in the debug output, very frustrating! For debugging purposes I would suggest turning the caching off temporarily.
In the file:
magento/app/code/local/CompanyName/ModuleName/etc/config.xml
the field must be ModuleName to work (version 1.1.8)
December 16th, 2008 at 3:59 amYour blog template is quite broken in Opera - I don’t get either of your sidebars
February 1st, 2009 at 2:25 pmThanks for that - So much clearer than the official docs!
February 6th, 2009 at 9:42 amI copied and pasted what I found on this site. I am using v 1.2.0.2.
I’m getting this in my soap response:
****
Uncaught SoapFault exception: [4] Resource path is not callable
****
What could be the problem? Email me if you can help.
February 7th, 2009 at 5:48 pmJust a note: the config.xml file incorrectly (well, didnt work for me!) has tag “test” under models. I had to change this to “modulename” (Also, my codebase goes app/etc/Modules not app/Modules/etc - maybe a recent change.)
One question… how do you get arguments to work? if i try to pass a parameter to the methodName call, it says “bad parameters”. Is the method signature the only place you need to list the API parameters?
Thanks!
February 17th, 2009 at 1:48 pmlast note, I promise: Arguments work as expected: I was using xmlrpc and (as opposed to what the magento docs say) you have to wrap the argument as an array - even if there is just one.
Thanks again!
February 25th, 2009 at 10:41 amHello,
Thanks for this tutorial.
But now, how do you call api?
I other word, what is the method name for the api call?
I Try this without sucess:
$client->call(’call’, array($session, ‘modulename/objectmodel_api.methodname’))
April 22nd, 2009 at 5:14 pmAh sorry, i don’t see:
And there you have it! You can call your method using resource_name.methodName like you would any other API call.
But what is the ressource name here?
April 22nd, 2009 at 5:17 pmHi,
We need to create a new order through a Web Services API. A Magento Custom API for sales order creation – sales_order.create – for a Customer Login, a Virtual Product SKU, quantity = 1, price = $X.XX, Customized Options, no billing, no shipping.
Another System will make this “sales_order.create” transaction via Magento XML-RPC Magento API.
Could you provide development services for this job, please?
Best,
Carlos Rocha
May 19th, 2009 at 10:53 amDoesn’t work for me in v1.3.1 Changed “test” to ModuleName too. Always get “invalid api path”. Been over and over it, no dice.
May 30th, 2009 at 6:51 amWeird… under system -> advanced -> advanced -> Disable Module Output I can see the module “CompanyName_ModuleName” and it’s enabled. So Magento knows it’s there.
Thinking maybe I need to define the API adapters to make accessible externally…
May 30th, 2009 at 6:54 amLooks like just another dead blog on the net. Pity.
May 31st, 2009 at 1:32 pmHey, have you given any more thought to this? I’m trying to implement it and keep getting “Resource path is not callable” when I try to make the API call. Not sure what I’m missing.
August 4th, 2009 at 8:32 am