Cara mengakses API Magento dari klien asli dengan JavaScript

9

Saya perlu mengakses Magento API dari aplikasi berbasis JavaScript lokal (Titanium Desktop) dan bertanya-tanya apa cara terbaik untuk melakukannya.

Apa yang saya temukan sejauh ini:

Pertanyaan:

  • Apakah mungkin untuk menukar mekanisme otentikasi ke sesuatu seperti otentikasi berbasis HMAC dengan kunci aplikasi dan rahasia? Apakah ada solusi yang sudah terbukti?
  • Jika tidak, apakah Aliran Agen Pengguna OAuth mungkin dengan Magento? Dokumentasi tidak menyebutkannya.
  • Apakah mungkin untuk menyerahkan kredensial pengguna dengan AJAX (Kebijakan Lintas-Asal bukan masalah di sini) untuk menyembunyikan sebagian besar proses otorisasi dari pengguna? Token akses kemudian dapat diekstraksi langsung dari respons.
Fabian Schmengler
sumber
OK, saya menemukan bahwa saya terlalu fokus pada REST, SOAP API harus menyelesaikan masalah saya, meskipun SOAP dengan JavaScript agak rumit. Ada perpustakaan untuk Titanium ( github.com/kwhinnery/Suds ), saya akan mencobanya dan memposting hasilnya di sini.
Fabian Schmengler

Jawaban:

8

Sunting: Menemukan cara yang lebih baik, lihat Solusi 2 di bawah ini

Seperti yang disebutkan dalam komentar, API SOAP adalah jalan yang harus ditempuh.

Solusi 1:

Suds bekerja untuk saya dengan sedikit modifikasi (Penggunaan Titanium.Network.HTTPClientbukan XMLHttpRequest), tetapi tidak lebih dari membuat amplop SOAP untuk panggilan dan mengembalikan seluruh respons XML.

Implementasi Bukti-Konsep, menggunakan jQuery Ditangguhkan untuk chaining permintaan:

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

Contoh penggunaan:

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

Solusi 2:

Ternyata menulis adaptor API sendiri bisa sangat mudah. Dengan contohcore-hack ini(tautan mati) Saya dapat menulis modul bersih untuk adaptor JSON-RPC berdasarkan Zend_Json_Server. Ia menggunakan Otentikasi dan ACL yang sama dengan API SOAP dan XML-RPC.

Untuk menggunakan titik masuk /api/jsonrpc, controller baru harus ditambahkan ke apirute:

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

Pembaruan 02/2015: Tautan di atas sudah mati sekarang, jadi saya membuka sumber JSON-RPC adaptor saya sebagai ekstensi lengkap: https://github.com/sgh-it/jsonrpc

Klien JS saya sekarang terlihat seperti ini (sekali lagi dengan JQuery.Deferred, tetapi tidak ada perpustakaan pihak ketiga tambahan untuk 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;
    };
};

Perhatikan bahwa semua metode setelah masuk disalurkan melalui call. The methodparameter adalah sesuatu seperti sales_order.list, yang argsparameter array atau objek dengan argumen metode.

Contoh penggunaan:

        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
sumber
Bagaimana cara mengkonfigurasi titik akhir dalam skrip Anda?
Mohamed
Anda harus mengubah definisi router frontend di config.xml(jika Anda tidak ingin menggunakan apirute, Anda juga dapat menggunakan rute kustom sebagai gantinya, mendefinisikannya seperti yang Anda lakukan dalam modul Magento lainnya
Fabian Schmengler
Di mana saya dapat meletakkan kode ini di
magento
Petunjuk instalasi ada di sana: github.com/sgh-it/jsonrpc
Fabian Schmengler
Dan kode JavaScript jelas bukan milik Magento tetapi di klien eksternal
Fabian Schmengler