Die Magento REST-API erweitern

Magento API erweitern

Die Magento REST API ist für die Anbindung von Shops an externe Systeme ein praktisches Werkzeug. Sie kann zur Datenpflege genutzt werden, zum Beispiel um Lagerbestände zu aktualisieren. In Apps kann auf den Katalog zugegriffen werden. Fast noch besser: Man kann die API um eigene Ressourcen erweitern! So wird Sie noch mächtiger und Shops deutlich flexibler.

Inhalt

Warum erweitern?

Die Magento API kann sowohl für lesende sowie schreibende Zwecke eingesetzt werden. Den Möglichkeiten sind keine Grenzen gesetzt. Im Verbund mit anderen Systemen kann viel Funktionalität erzeugt werden. So stehen sehr umfassende Varianten der Anbindung externer Systeme bereit. Unabhängig von alternativen Lösungen ein paar Beispiele zur Inspiration:

  • fehlgeschlagene Logins per API zur Verfügung stellen
  • Daten zu Aufträgen abrufbar machen (hochgeladene Daten zum Beispiel)
  • Loadbalancer können bei Problemen Memcache Servern o.ä. deaktivieren
  • etc

Wenn Sie hier Hilfe oder Unterstützung benötigen, stehe ich gerne für Sie als Magento Entwickler bereit. Kontaktieren Sie mich unverbindlich. Für all dies benötigt man lediglich eine API Ressource.

Ressource konfigurieren

Eine Ressource ist im Magento Kontext ein Model. In der config.xml einer Extension ist keine spezielle Konfiguration notwendig. Die Definition für Model-Klassen reicht aus. Die Ressource-Konfiguration erfolgt über die Datei api2.xml.

Die Datei definiert verschiedene Eigenschaften. Im Beispiel wird unter resource_groups eine Gruppe für die neue Ressource angelegt. Die Extension erzeugt insgesamt eine Ressource für »Featuredproducts«. Die Gruppierung ist zweitrangig. Ein sinnvolles Beispiel ist die Gruppe »catalog«. Sie kann die Ressource Catalog, Product etc. logisch zusammenfassen.

        <resource_groups>
            <apiexample translate="title" module="apiexample">
                <title>APIExample</title>
                <sort_order>10</sort_order>
            </apiexample>
        </resource_groups>

Anschließend werden Ressourcen im Knoten resources definiert. Für jede API-Ressource werden verschiedene Angaben hinterlegt. Da gibt es die Zuordnung zu einer Gruppe, die Definition des zu verwendenden Models, ein Titel, der im Backend angezeigt wird, sowie den Sortierungsschlüssel. Die Angaben sind weitestgehend selbsterklärend.

            <apiexample translate="title" module="apiexample">
                <group>apiexample</group>
                <model>apiexample/api2_featuredproduct</model>
                <title>API extension sample</title>
                <sort_order>10</sort_order>

Bedeutender sind die Knoten privileges, attributes und routes. Unter »privileges« werden die unterstützten Rechte festgelegt. Dies sind »retrieve« für den Abruf von Daten, »create« zum erzeugen von Entitäten, »update« zum aktualisieren und »delete« zum löschen von Datensätzen. Diese ergeben sich aus dem REST-Kontext. Festgelegt werden die Rechte für die Rollen »guest«, »customer« und »admin«. In dem Beispiel wäre es sinnvoll einen Gast »featured Products« lesen, einen Admin diese erzeugen zu lassen.

                <privileges>
                    <guest>
                        <retrieve>1</retrieve>
                    </guest>
                </privileges>

Ein weiterer Teil der Zugriffsbeschränkung ist der Knoten attributes. Für die festgelegten Models wird definiert welche Attribute existieren. Pro Rolle kann dann der Zugriff gesteuert werden. Sinnvoll im Zusammenhang mit Produkten wäre bspw. einem Gast (»guest«) den Abruf der normalen Preise zu erlauben. Ein Kunde (»customer«) könnte zusätzlich Zugriff auf kundenspezifische Preise erhalten.

                <attributes translate="title" module="apiexample">
                    <entity_id>Product ID</entity_id>
                    <name>Name</name>
                    <price>Preis</price>
                    <sku>SKU</sku>
                </attributes>

Zuguter letzt folgt die Definition der Route. Unter welche URL wird die Ressource angesprochen?

                <routes>
                    <route>
                        <route>/apiexample/featuredproduct</route>
                        <action_type>collection</action_type>
                    </route>
                </routes>

Die komplette URL setzt sich aus der base_url vom Onlineshop, »api/rest« und der  angegebenen Definition zusammen. Für das Beispiel ergibt das:

http://<baseurl>/api/rest/apiexample/featuredproduct

Die komplette api2.xml zur besseren Übersicht:

<?xml version="1.0" ?>
<config>
    <api2>
        <resource_groups>
            <apiexample translate="title" module="apiexample">
                <title>APIExample</title>
                <sort_order>10</sort_order>
            </apiexample>
        </resource_groups>

        <resources>
            <apiexample translate="title" module="apiexample">
                <group>apiexample</group>
                <model>apiexample/api2_featuredproduct</model>
                <title>API extension sample</title>
                <sort_order>10</sort_order>

                <privileges>
                    <guest>
                        <retrieve>1</retrieve>
                    </guest>
                </privileges>

                <attributes translate="title" module="apiexample">
                    <entity_id>Product ID</entity_id>
                    <name>Name</name>
                    <price>Preis</price>
                    <sku>SKU</sku>
                </attributes>

                <routes>
                    <route>
                        <route>/apiexample/featuredproduct</route>
                        <action_type>collection</action_type>
                    </route>
                </routes>

                <versions>1</versions>
            </apiexample>
        </resources>
    </api2>
</config>

Model erzeugen

Die Ressource wird von der Klasse Mage_Api2_Model_Resource abgeleitet. Zumindest in unserem Beispiel sind keine Methoden notwendig:

class Luckyduck_Apiexample_Model_Api2_Featuredproduct extends Mage_Api2_Model_Resource
{}

Die API arbeitet mit Objekten, die sich aus der erzeugten Ressource ergeben. Je nachdem ob die Rolle »admin«, »customer« oder »guest« zugreift, werden unterschiedliche Klassen verwendet:

  • <Ressource-Klasse>_Rest_Admin_V1
  • <Ressource-Klasse>_Rest_Customer_V1
  • <Ressource-Klasse>_Rest_Guest_V1

Das ermöglicht nicht nur auf Rechteebene im Verhalten einzugreifen. Es kann auch für jede Rolle ein eigenes Verhalten festgelegt werden. Um das Beispiel noch einmal aufzugreifen, könnte zum Beispiel der Gast ein Produkt mit einem Preis laden und vorbereiten. Die Klasse für die Rolle »customer« hingegen benötigt zusätzliche Logik, da dort kundenindividuelle Preise geladen werden. In der Beispielextension reicht die Klasse für den Gast aus:


class Luckyduck_Apiexample_Model_Api2_Featuredproduct_Rest_Guest_V1
    extends Luckyduck_Apiexample_Model_Api2_Featuredproduct
{
    public function _retrieveCollection()
    {
        $collection = Mage::getModel('catalog/product')->getCollection();
        $collection->addAttributeToSelect('*');
        // $collection->[..your filter for featured products here..]

        $featuredProducts = array();
        foreach ($collection as $product) {
            $featuredProducts[] = array(
                'entity_id' => $product->getId(),
                'name' => $product->getName(),
                'price' => $product->getPrice(),
                'sku' => $product->getSku()
            );
        }

        return $featuredProducts;
    }
}

Von zentraler Bedeutung ist die Methode _retrieveCollection(). Sie wird aufgerufen und muss die Daten als Array zurückgeben. Das Beispiel lädt alle vorhandenen Produkte. Es fehlt ein konkreter Filter, um ausschließllich als »featured« gekennzeichnete Produkte zu berücksichtigen.

Konfiguration im Backend

Im Backend wird der Zugriff konfiguriert, der in der Datei api2.xml vorbereitet wurde. Zwei Punkte sind entscheidend. Zuerst wird unter System→Web Services→REST – Roles der Zugriff für die Rolle »guest« festgelegt.

edit-guest-role

Unser Beispiel bietet ausschließlich »Retrieve« an. Dies muss ausgewählt werden. Im zweiten Schritt werden unter System→Web Services→REST – Roles die Regeln für die einzelnen Attribute konfiguriert. Für das Beispiel sind alle für lesenden (»Read«) Zugriff auszuwählen:

edit-attribut-rules

Wurde alles korrekt umgesetzt, sollte der Abruf per HTTP funktionieren. Dort müssen Produkte aufgelistet werden, zum Beispiel wie folgt:

api-result

Extension herunterladen

Die Beispiel Extension kann über Github heruntergeladen werden. Ist nur ein grundlegendes Beispiel, reicht zur Demonstration der Basisidee aber aus. Zum Github Repository →

Fazit

Die Magento API kann durch eigene Erweiterungen noch sinnvoller werden. Speziell die Arbeit mit REST APIs empfinde ich persönlich als angenehm und übersichtlich, besser als zum Beispiel die SOAP-Variante. Was hier noch nicht berücksichtigt wurde, ist die Authentifizierung, welche für reale Anwendungsfälle  und die Arbeit mit den Rollen »customer« und »admin« noch fehlt. Das wird dann in einem separaten Artikel behandelt.