Come accedere all'API Magento dal client nativo con JavaScript


9

Devo accedere all'API Magento da un'applicazione locale basata su JavaScript (Titanium Desktop) e chiedersi quale sia il modo migliore per farlo.

Quello che ho scoperto finora:

Domande:

  • È possibile scambiare il meccanismo di autenticazione con qualcosa come l'autenticazione basata su HMAC con chiave dell'applicazione e segreto? Ci sono anche soluzioni comprovate?
  • In caso contrario, il flusso dell'agente utente OAuth è possibile con Magento? La documentazione non lo menziona.
  • È possibile inviare le credenziali dell'utente con AJAX (qui la politica incrociata non è un problema) per nascondere all'utente la maggior parte del processo di autorizzazione? Il token di accesso potrebbe quindi essere estratto direttamente dalla risposta.

OK, ho scoperto che ero troppo concentrato su REST, l'API SOAP dovrebbe risolvere il mio problema, sebbene SOAP con JavaScript sia piuttosto ingombrante. C'è una libreria per Titanium ( github.com/kwhinnery/Suds ), lo proverò e pubblicherò i risultati qui.
Fabian Schmengler,

Risposte:


8

Modifica: trovato un modo migliore, vedere la Soluzione 2 di seguito

Come menzionato nel commento, l'API SOAP è la strada da percorrere.

Soluzione 1:

Suds ha funzionato per me con lievi modifiche (utilizzo Titanium.Network.HTTPClientinvece di XMLHttpRequest), ma non è molto più che creare una busta SOAP per la chiamata e restituire l'intera risposta XML.

Implementazione di Proof-of-Concept, utilizzando jQuery Deferred per il concatenamento di richieste:

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;
    };
};

Esempio di utilizzo:

        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);
        });

Soluzione 2:

Si è scoperto che scrivere un proprio adattatore API può essere davvero facile. Con l'esempio diquesto core-hack(dead link) Sono stato in grado di scrivere un modulo pulito per un adattatore JSON-RPC basato su Zend_Json_Server. Utilizza la stessa autenticazione e ACL delle API SOAP e XML-RPC.

Per utilizzare il punto di ingresso /api/jsonrpc, è necessario aggiungere il nuovo controller al apipercorso:

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

Aggiornamento 02/2015: il link sopra è morto ora, quindi apro la mia scheda JSON-RPC come estensione completa: https://github.com/sgh-it/jsonrpc

Il mio client JS ora appare così (di nuovo con JQuery.Deferred, ma nessuna libreria di terze parti aggiuntiva per 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;
    };
};

Si noti che tutti i metodi dopo l'accesso vengono instradati call. Il methodparametro è qualcosa di simile sales_order.list, il argsparametro un array o un oggetto con gli argomenti del metodo.

Esempio di utilizzo:

        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);
                }
            );
        });

Come configurare l'endpoint nel tuo script?
Akrramo,

Devi modificare la definizione del router frontend in config.xml(se non vuoi usare il apipercorso, puoi anche usare un percorso personalizzato, definiscilo come faresti in qualsiasi altro modulo Magento
Fabian Schmengler

Dove posso inserire questo codice in magento
er.irfankhan11,

Le istruzioni di installazione ci sono: github.com/sgh-it/jsonrpc
Fabian Schmengler,

E il codice JavaScript ovviamente non appartiene a Magento ma al client esterno
Fabian Schmengler,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.