Comment accéder à l'API Magento à partir d'un client natif avec JavaScript

9

Je dois accéder à l'API Magento à partir d'une application locale basée sur JavaScript (Titanium Desktop) et je me demande quelle est la meilleure façon de le faire.

Ce que j'ai découvert jusqu'à présent:

Des questions:

  • Est-il possible d'échanger le mécanisme d'authentification vers quelque chose comme l'authentification basée sur HMAC avec la clé d'application et le secret? Existe-t-il même des solutions éprouvées?
  • Sinon, le flux d'agent utilisateur OAuth est-il possible avec Magento? La documentation ne le mentionne pas.
  • Est-il possible de soumettre les informations d'identification de l'utilisateur avec AJAX (Cross-Origin-Policy n'est pas un problème ici) pour masquer la plupart du processus d'autorisation à l'utilisateur? Le jeton d'accès pourrait alors éventuellement être extrait directement de la réponse.
Fabian Schmengler
la source
OK, j'ai découvert que j'étais trop concentré sur REST, l'API SOAP devrait résoudre mon problème, bien que SOAP avec JavaScript soit un peu lourd. Il existe une bibliothèque pour Titanium ( github.com/kwhinnery/Suds ), je vais l'essayer et publier les résultats ici.
Fabian Schmengler

Réponses:

8

Edit: Trouvé un meilleur moyen, voir la solution 2 ci-dessous

Comme mentionné dans le commentaire, l'API SOAP est la voie à suivre.

Solution 1:

Suds a fonctionné pour moi avec une légère modification (utilisation de Titanium.Network.HTTPClientau lieu de XMLHttpRequest), mais cela ne fait pas beaucoup plus que de créer une enveloppe SOAP pour l'appel et de renvoyer la réponse XML entière.

Implémentation de la preuve de concept, utilisant jQuery Deferred pour le chaînage des demandes:

Service.MagentoClient = function()
{
    var self = this;
    var suds = new SudsClient({
        endpoint : "http://the-magento-host/api/v2_soap/",
        targetNamespace : "urn:Magento",
    });

    self.login = function() {
        var deferred = new $.Deferred();
        var args = {
            username : 'the-username',
            apiKey: 'the-api-key'
        };
        suds.invoke("login", args, function(xmlDoc) {
            self.sessionId = $(xmlDoc).find("loginReturn").text();
            deferred.resolve({});
            //TODO reject if no sessionid returned
        });
        return deferred;
    };

    self.setStatus = function(orderId, status, comment, notify) {
        var deferred = new $.Deferred();
        if (!self.sessionId) {
            deferred.reject({ error: 'Login not successful.' });
            return;
        }
        var args = {
            sessionId        : self.sessionId,
            orderIncrementId : orderId,
            status           : status,
            comment          : comment,
            notify           : notify
        }
        suds.invoke("salesOrderAddComment", args, function(xmlDoc) {
            var success = $(xmlDoc).find("salesOrderAddCommentResponse").text();
            if (success) {
                deferred.resolve({});
            } else {
                deferred.reject({ error: 'Update not successful.' });
            }

        });
        return deferred;
    };
};

Exemple d'utilisation:

        var magento = new Service.MagentoClient();
        magento.login().then(function() {
            magento.setStatus('100000029', 'complete', 'soap test');
        }).then(function() {
            alert('Update successful');
        }, function(reject) {
            alert('Update failed: ' + reject.error);
        });

Solution 2:

Il s'est avéré que l'écriture d'un propre adaptateur API peut être très facile. Avec l'exemple dece core-hack(lien mort) J'ai pu écrire un module propre pour un adaptateur JSON-RPC basé sur Zend_Json_Server. Il utilise la même authentification et ACL que les API SOAP et XML-RPC.

Pour utiliser le point d'entrée /api/jsonrpc, le nouveau contrôleur doit être ajouté à l' apiitinéraire:

<config>
    <frontend>
        <routers>
            <api>
                <args>
                    <modules>
                        <my_jsonrpc before="Mage_Api">My_JsonRpc_Api</my_jsonrpc>
                    </modules>
                </args>
            </api>
        </routers>
    </frontend>
</config>

Mise à jour 02/2015: le lien ci-dessus est mort maintenant, j'ouvre donc mon adaptateur JSON-RPC comme une extension complète: https://github.com/sgh-it/jsonrpc

Mon client JS ressemble maintenant à ceci (encore une fois avec JQuery.Deferred, mais pas de bibliothèques tierces supplémentaires pour l'API):

/**
 * Client for the Magento API
 */
Service.MagentoClient = function()
{
    var self = this;

    /**
     * @param string   method    the remote procedure to call
     * @param object   params    parameters for the RPC
     * @param callback onSuccess callback for successful request. Expects one parameter (decoded response object)
     * @param callback onError   callback for failed request. Expects one parameter (error message)
     * 
     * @return void
     */
    self.jsonRpc = function(method, params, onSuccess, onError) {
        var request = {
            method : method,
            params : params,
            jsonrpc : "2.0",
            id : 1
        };

        var options = {
            entryPoint : config.magentoClient.entryPoint,
            method: 'post',
            timeout: config.magentoClient.timeout
        };

        var httpClient = Titanium.Network.createHTTPClient();
        httpClient.onload = function(e) {
            try {
                var response = JSON.parse(this.responseText);
            } catch (jsonError) {
                return onError(jsonError);
            }
            if (response.error) {
                if (response.error.code == 5) { // session expired
                    self.sessionId = null;
                }
                return onError(response.error.message);
            }
            onSuccess(response);
        };
        httpClient.onerror = function(e) {
            onError(e.error + '; Response:' + this.responseText);
        };
        httpClient.setTimeout(options.timeout);

        if (httpClient.open(options.method, options.entryPoint)) {
            httpClient.setRequestHeader("Content-type", "application/json");
            httpClient.send(JSON.stringify(request));
        } else {
            onError('cannot open connection');
        }

    }
    /**
     * Retrieve session id for API
     * 
     * @return JQuery.Deferred deferred object for asynchronous chaining
     */
    self.login = function() {
        var deferred = new $.Deferred();
        if (self.sessionId) {
            deferred.resolve();
            return deferred;
        }
        var loginParams = config.magentoClient.login;
        try {
            self.jsonRpc('login', loginParams, function(response) {
                if (response && response.result) {
                    self.sessionId = response.result;
                    deferred.resolve();
                } else {
                    deferred.reject('Login failed.');
                }
            }, function(error) {
                deferred.reject(error);
            });
        } catch (rpcError) {
            deferred.reject(rpcError);
        }
        return deferred;
    };
    /**
     * Updates order states in Magento
     *
     * @param string method   name of the remote method
     * @param object args     arguments for the remote method
     * 
     * @return JQuery.Deferred deferred object for asynchronous chaining
     */
    self.call = function(method, args) {
        var deferred = new $.Deferred();
        if (!self.sessionId) {
            deferred.reject('No session.');
            return;
        }
        var callParams = {
            sessionId : self.sessionId,
            apiPath   : method,
            args      : args
        };
        try {
            self.jsonRpc('call', callParams, function(response) {
                deferred.resolve(response.result);
            }, function(error) {
                deferred.reject(error);
            });
        } catch (rpcError) {
            deferred.reject(rpcError);
        }

        return deferred;
    };
};

Notez que toutes les méthodes après la connexion sont acheminées call. Le methodparamètre est quelque chose comme sales_order.list, le argsparamètre un tableau ou un objet avec les arguments de la méthode.

Exemple d'utilisation:

        var filters = [];
        var magento = new Service.MagentoClient();
        magento.login().then(function() {
            magento.call('sales_order.list', [filters]).then(
                function(orders) {
                    // do something with the response
                }, function(error) {
                    alert('Magento API error: ' + error);
                }
            );
        });
Fabian Schmengler
la source
Comment configurer le point de terminaison dans votre script?
Mohamed
Vous devez changer la définition du routeur frontal dans config.xml(si vous ne voulez pas utiliser l' apiitinéraire, vous pouvez également utiliser un itinéraire personnalisé à la place, définissez-le comme vous le feriez dans n'importe quel autre module Magento
Fabian Schmengler
Où puis-je mettre ce code dans magento
er.irfankhan11
Les instructions d'installation sont là: github.com/sgh-it/jsonrpc
Fabian Schmengler
Et le code JavaScript n'appartient évidemment pas à Magento mais au client externe
Fabian Schmengler