People often talk about Magento having a “SOAP” API. SOAP is a series of protocols that, from one point of view, is designed to allow programmers to call a function on one computer, and have it executed on another computer. XML-RPC is a simpler, earlier protocol that does similar things, and people talk about Magento having an XML-RPC API as well. These people, although well intentioned, aren’t telling the whole truth.
There’s no such thing as The Magento SOAP API, or The Magento XML-RPC API.
What Magento does have is The Core API. The Magento core teams loves abstractions. What they’ve done with the Magento Core API is define their own, abstract programming language. This language has resources. Each resource has a callable method which will perform some common task in Magento. This programming language is abstract because it has no native implementation.
There is no way to write a program that uses the Magento API. Instead, the core team has written “adapters” (also known as “connectors”) that allow you to access the API via known protocols. There’s an adapter for SOAP. There’s an adapter for XML-RPC. Once you know your way around the API, it would be possible to build a RESTful adapter, or an adapter for the janky unstructured XML based API you’ve cobbled together internally. (Apologies to people unable to see the difference between the last two).
This is a small quibble. At the end result end-user-programmers have the ability to do things with Magento via SOAP or XML-RPC. However, keeping this point of view in mind will help you understand the API implementation, and the techniques we’ll be exploring today.
Cost of Abstraction
This abstraction allowed the core team to build out a single API implementation in native PHP code, and then write single adapters for SOAP and XML-RPC. This guaranteed the current APIs, as well as any future APIs, would have identical methods. That is, there’s no easy way to create a method for the SOAP API that doesn’t exist for the XML-RPC API. This is a smart move for a startup that can’t anticipate how their system will be used out in the wild.
Like all things programming, this technique is not without its tradeoffs. The one we’re interested in today is performance. Magento has inserted two systems between the end-user-programmer and the non-API related PHP Magento code that does the work for the API methods. No matter how many optimizations happen, a call made through the API will always be slower than a call made via native PHP code.
What we’ll be looking at today is a technique for skipping the API adapter layer and making calls directly to the native PHP API models. This brings huge performance boosts, while still using the correct business logic encapsulated in the API methods.
The Business of Business Logic
If you’ve got a little Magento experience under your belt, you may be thinking
Why bother? If we’re writing native PHP code why not just use the Magento objects? Why bother with the API at all?
Although it’s often the only way to do what you want in Magento, the key disadvantage to using the native PHP objects in Magento is the lack of consistant rules for enforcing Magento’s business logic, particularly between versions of Magento.
For example, if you’re using the native
sales/order object hierarchy to fetch order information in Magento, it’s up to you, as the end-programmer-user, to load the correct order support information (address, gift messages, etc.). Sometimes the native objects will have methods to do this, sometimes they won’t. This problem multiplies when it comes to saving object information into the database. When using the native PHP objects it’s possible to put Magento into a state not anticipated by the core team, or by their tests.
On the other hand, the API methods have been explicitly designed for use by outsiders. While they’re only a subset of Magento’s entire functionality, they’re a stable subset. Things that are tribal knowledge to a developer using the native PHP Magento objects are hard-coded into the API methods. For a company that’s as secretive about their development process as Magento (see also: Google, Apple, etc.), the API methods are the closest we’ll come to The Right™ way to do something.
As always, there’s no hard and fast rule when (if ever) you should use the techniques provided below over native PHP code, or the same calls made through the SOAP adapters. This is just another tool in the arsenal of a Magento developer. It’s up to you to decide the best course of action for your code and your company.
Anatomy of a Magento API Call
Every call to the Magento API is made up of a resource and a method. Think of API resources like a class, and API methods like methods on those classes.
For example, to create a customer using the API, you use the
customer resource, and the
create method. Each of these resource/method pairs resolves to a model/method pair on a special Magento API resource model object. These resource model objects are separate from the Magento CRUD resource models. You can use the Developer Manual extension to quickly jump to these method definitions. That said, it’s useful to know how these methods resolve. Below we’ll explore how the API resource
is resolved to the native PHP object call
$results = Mage::getModel('customer/customer_api')->create(...);
Warning: We’re glossing over some important details here. While this is an adequate guide for tracking down where a specific API call resolves to, it’s not a complete guide for setting up a new API resource and method of your own.
Magento’s api.xml Files
In order to expose an API resource and method(s) in Magento, a module defines an
api.xml configuration file.
$ find app/code/core -name 'api.xml' app/code/core/Mage/Api/etc/api.xml app/code/core/Mage/Catalog/etc/api.xml app/code/core/Mage/CatalogInventory/etc/api.xml app/code/core/Mage/Checkout/etc/api.xml app/code/core/Mage/Core/etc/api.xml app/code/core/Mage/Customer/etc/api.xml app/code/core/Mage/Directory/etc/api.xml app/code/core/Mage/Downloadable/etc/api.xml app/code/core/Mage/GiftMessage/etc/api.xml app/code/core/Mage/Sales/etc/api.xml app/code/core/Mage/Tag/etc/api.xml
These files can be used to look up the Magento model that’s used to implement an API call. In each file, the nodes at
<config> <api> <resources> <...> </resources> </api> </config>
represent an API resource. In our example above, the node for the
customer resource can be found at
<!-- File: app/code/core/Mage/Customer/etc/api.xml --> <config> <api> <resources> <customer translate="title" module="customer"> <!-- ... --> </customer> </resources> </api> </config>
In general, an API resource name (
customer) usually indicates which Magento module its
api.xml file will be located in (
Mage_Customer), but this is only a convention and shouldn’t be trusted as a canonical way of finding a resource’s
API Resource, Meet Magento Model
Within each resource node, you’ll find a
<!-- File: app/code/core/Mage/Customer/etc/api.xml --> <customer translate="title" module="customer"> <model>customer/customer_api</model> <!-- ... --> </customer>
This model node contains a class alias for the Magento model that this particular resource uses. So, this tells us a Magento Core API
customer resource is implemented with a
Mage::getModel('customer/customer_api'); model. We’re half way there!
Before we move on to deriving a method name, there’s a gotcha to be careful of. If you were using the earliest version of the Magento Core API, you may have made an API call like
However, searching through the
api.xml resource nodes yields no
<category/> node. What gives?
In addition to the
<resource/> node, each
api.xml file may also contain a
<config> <api> <resources_alias> <!-- ... --> </resource_alias> </api> </config>
Each sub-node here can be used to alias one resource to another. For example, in the
api.xml file, we can see there’s a resource alias for the category node
<!-- File: app/code/core/Mage/Catalog/etc/api.xml --> <config> <api> <resources_alias> <category>catalog_category</category> <!-- ... --> </resource_alias> </api> </config>
The above configuration means the API call to
is equivalent to the API call to
meaning if we consult the
api.xml file again
<!-- File: app/code/core/Mage/Catalog/etc/api.xml --> <config> <api> <resources> <catalog_category translate="title" module="catalog"> <model>catalog/category_api</model> </catalog> </resources> </api> </config>
we’ll know that both API calls resolves to the following native PHP Magento model.
$api_resource_model = Mage::getModel('catalog/category_api');
Finding the Method
Now that we know which Magento model our API resource model resolves to, our next step is finding which PHP method our API method resolves to.
Looking again at our
api.xml file, we can see that each distinct resource node (
<catalog_category>, etc.) has a
<!-- File: app/code/core/Mage/Customer/etc/api.xml --> <config> <api> <resources> <customer> <methods> <!-- ... --> </method> </customer> </resource> </api> </config>
Each sub-node of methods will expose a method of the same name on the resource model object. For example, the
info method is exposed by the following configuration
<!-- File: app/code/core/Mage/Customer/etc/api.xml --> <customer> <methods> <info><!-- ... --></info> </method> </customer>
With this node in place, the API adapter will pass through the method name to the resource model object.
That is to say, if we consider our API call to
the API adapter will
- Translate the
customerresource to the
- Instantiate a
Take the API method,
create, and look for a corresponding node under the
If it find the node, call the
createmethod of the just instantiated
customer/customer_apimodel, and then serialize the results to return via the API
This means if you’d like to skip the overhead and authentication of the SOAP or XML-RPC APIs but still get the benefits of the API’s business logic, you can replicate the call yourself by using the following PHP code (in a Magento bootstrapped environment, of course)
$model = Mage::getModel('customer/customer_api'); $results = $model->create($array_of_customer_data);
Before we wrap up there’s one last “gotcha” regarding method names. Many Magento API resources contain a method named
list. However, if you were to execute the following PHP code
$model = Mage::getModel('customer/customer_api'); $results = $model->list();
you’d get a PHP error. That’s because
list is a reserved PHP keyword. You can’t use
list as a constant, class name, function, or method name.
So how can Magento use
list as an API method name? Let’s take a look at the
api.xml configuration of a
<!-- File: app/code/core/Mage/Customer/etc/api.xml --> <methods> <list translate="title" module="customer"> <title>Retrieve customers</title> <method>items</method> <acl>customer/info</acl> </list> </methods>
As you can see above, the
api.xml configuration supports a sub-node of an individual
<methods/> sub-node named
<method/>. (our apologies for that accurate, yet absysmal sentence).
So while the configuration exposes the
customer.list API method, the actual PHP method called is the configured
items method, making the PHP you should use
$model = Mage::getModel('customer/customer_api'); $results = $model->items($filters);
This syntax is not just reserved for the
list method, so always make sure you check your XML for the optional
It’s not always easy being a Magento developer. The ecommerce problem domain is sprawling and there’s few companies who’ve chosen to fully tackle and understand its complexities and share those results with the world. If you can push your way past Magento’s complicated abstractions you’ll find a wealth of proven programming models for ecommerce. The Magento Core API represents the safest, stablest way to interact with your Magento system. While it won’t solve every problem, by using it wherever possible you’ll have fewer problems due to working, but incomplete, custom code.