├── LICENSE ├── README.md ├── index.js ├── lib ├── attributes.js ├── cart.js ├── categories.js ├── category_products.js ├── configurable_children.js ├── configurable_options.js ├── customers.js ├── directory.js ├── log.js ├── orders.js ├── product_media.js ├── products.js ├── rest_client.js ├── reviews.js ├── stock_items.js ├── tax_rates.js └── tax_rules.js ├── magento2-rest-client.iml ├── package.json └── test └── integration ├── categories.integration.test.js ├── product_media.integration.test.js └── products.integration.test.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Marko Novak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Magento2 REST client 2 | 3 | 4 | ### Stay connected 5 | 6 | [![GitHub Repo stars](https://img.shields.io/github/stars/vuestorefront/vue-storefront?style=social)](https://github.com/vuestorefront/vue-storefront) 7 | [![Twitter Follow](https://img.shields.io/twitter/follow/vuestorefront?style=social)](https://twitter.com/vuestorefront) 8 | [![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UCkm1F3Cglty3CE1QwKQUhhg?style=social)](https://www.youtube.com/c/VueStorefront) 9 | [![Discord](https://img.shields.io/discord/770285988244750366?label=join%20discord&logo=Discord&logoColor=white)](https://discord.vuestorefront.io) 10 | 11 | This Node.js library enables JavaScript applications to communicate with Magento2 sites using their REST API. 12 | This module based on the magento2-rest-client module created by Marko Novak (2016). 13 | 14 | This module is used by the [Vue Storefront - first Progressive Web App for eCommerce](https://github.com/DivanteLtd/vue-storefront). 15 | 16 | **NOTE: the library is not finished yet! Only a subset of Magento2 API is currently implemented.** 17 | 18 | 19 | ## Installation 20 | 21 | The library can be installed using the Npm package manager: 22 | 23 | ``` 24 | npm install --save github:DivanteLtd/magento2-rest-client 25 | ``` 26 | 27 | ## Usage 28 | 29 | The code sample below shows the usage of the library: 30 | 31 | ```javascript 32 | var Magento2Client = require('magento2-rest-client').Magento2Client; 33 | 34 | var options = { 35 | 'url': 'http://www.test.com/index.php/rest', 36 | 'consumerKey': '', 37 | 'consumerSecret': '', 38 | 'accessToken': '', 39 | 'accessTokenSecret': '' 40 | }; 41 | var client = Magento2Client(options); 42 | client.categories.list() 43 | .then(function (categories) { 44 | assert.equal(categories.parentId, 1); 45 | }) 46 | ``` 47 | 48 | You can extend the API by adding Your own modules or adding methods to the existing modules! 49 | ```javascript 50 | var Magento2Client = require('magento2-rest-client').Magento2Client; 51 | 52 | var options = { 53 | 'url': 'http://www.test.com/index.php/rest', 54 | 'consumerKey': '', 55 | 'consumerSecret': '', 56 | 'accessToken': '', 57 | 'accessTokenSecret': '' 58 | }; 59 | var client = Magento2Client(options); 60 | 61 | client.addMethods('categories', function (restClient) { 62 | var module = {}; 63 | module.listEx = function () { 64 | return restClient.get('/categories'); 65 | } 66 | return module; 67 | } 68 | ) 69 | 70 | client.addMethods('newModule', function (restClient) { 71 | var module = {}; 72 | module.newMethod = function () { 73 | return restClient.post('/custom_magento_api_endpoint'); 74 | } 75 | return module; 76 | } 77 | ) 78 | 79 | client.categories.listEx() 80 | .then(function (categories) { 81 | assert.equal(categories.parentId, 1); 82 | }) 83 | client.newModule.newMethod() 84 | .then(function (resultJson) { 85 | }) 86 | ``` 87 | 88 | 89 | ## Contributing 90 | 91 | ### usefull resources 92 | 93 | Magento API with Swagger: https://devdocs.magento.com/swagger/ 94 | 95 | Entry Page of REST API Documentation of Magento: https://devdocs.magento.com/guides/v2.3/rest/bk-rest.html 96 | filter response: https://devdocs.magento.com/guides/v2.3/rest/retrieve-filtered-responses.html 97 | 98 | ## Credit 99 | 100 | This Repository is an independent fork of https://github.com/nouvak/magento2-rest-client created by Marko Novak. 101 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var RestClient = require('./lib/rest_client').RestClient; 4 | var categories = require('./lib/categories'); 5 | var attributes = require('./lib/attributes'); 6 | var products = require('./lib/products'); 7 | var productMedia = require('./lib/product_media'); 8 | var categoryProducts = require('./lib/category_products'); 9 | var configurableChildren = require('./lib/configurable_children'); 10 | var configurableOptions = require('./lib/configurable_options'); 11 | var taxRates = require('./lib/tax_rates'); 12 | var taxRules = require('./lib/tax_rules'); 13 | var stockItems = require('./lib/stock_items'); 14 | var customers = require('./lib/customers'); 15 | var directory = require('./lib/directory'); 16 | var cart = require('./lib/cart'); 17 | var orders = require('./lib/orders'); 18 | var reviews = require('./lib/reviews'); 19 | 20 | const MAGENTO_API_VERSION = 'V1'; 21 | 22 | module.exports.Magento2Client = function (options) { 23 | var instance = { 24 | addMethods (key, module) { 25 | var client = RestClient(options); 26 | if (module) { 27 | if (this[key]) 28 | this[key] = Object.assign(this[key], module(client)) 29 | else 30 | this[key] = module(client) 31 | } 32 | } 33 | }; 34 | 35 | options.version = MAGENTO_API_VERSION; 36 | 37 | var client = RestClient(options); 38 | 39 | instance.attributes = attributes(client); 40 | instance.categories = categories(client); 41 | instance.products = products(client); 42 | instance.productMedia = productMedia(client); 43 | instance.categoryProducts = categoryProducts(client); 44 | instance.configurableChildren = configurableChildren(client); 45 | instance.configurableOptions = configurableOptions(client); 46 | instance.stockItems = stockItems(client); 47 | instance.taxRates = taxRates(client); 48 | instance.taxRules = taxRules(client); 49 | instance.customers = customers(client); 50 | instance.cart = cart(client); 51 | instance.orders = orders(client); 52 | instance.directory = directory(client); 53 | instance.reviews = reviews(client); 54 | 55 | return instance; 56 | } 57 | -------------------------------------------------------------------------------- /lib/attributes.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function (searchCriteria) { 7 | var query = 'searchCriteria=' + searchCriteria; 8 | var endpointUrl = util.format('/products/attributes?%s', query); 9 | return restClient.get(endpointUrl); 10 | } 11 | 12 | module.create = function (categoryAttributes) { 13 | return restClient.post('/products/attributes', categoryAttributes); 14 | } 15 | 16 | module.update = function (attributeId, categoryAttributes) { 17 | var endpointUrl = util.format('/products/attributes/%d', attributeId); 18 | return restClient.put(endpointUrl, categoryAttributes); 19 | } 20 | 21 | module.delete = function (attributeId) { 22 | var endpointUrl = util.format('/products/attributes/%d', attributeId); 23 | return restClient.delete(endpointUrl); 24 | } 25 | 26 | return module; 27 | } 28 | -------------------------------------------------------------------------------- /lib/cart.js: -------------------------------------------------------------------------------- 1 | function isNumeric(val) { 2 | return Number(parseFloat(val)).toString() == val; 3 | } 4 | 5 | module.exports = function (restClient) { 6 | var module = {}; 7 | 8 | module.create = function (customerToken, customerId = null) { 9 | if (customerId) { 10 | return restClient.post('/customers/' + customerId + '/carts', {}, customerToken); 11 | } else { 12 | if (customerToken) { 13 | return restClient.post('/carts/mine', {}, customerToken); 14 | } else 15 | { 16 | return restClient.post('/guest-carts'); 17 | } 18 | } 19 | } 20 | module.update = function (customerToken, cartId, cartItem, adminRequest = false) { 21 | if (adminRequest) { 22 | return restClient.post('/carts/' + cartId + '/items/', { cartItem: cartItem }); 23 | } else { 24 | if (customerToken && isNumeric(cartId)) { 25 | return restClient.post('/carts/mine/items', { cartItem: cartItem }, customerToken); 26 | } else 27 | { 28 | return restClient.post('/guest-carts/' + cartId + '/items', { cartItem: cartItem }); 29 | } 30 | } 31 | } 32 | 33 | module.applyCoupon = function (customerToken, cartId, coupon, adminRequest = false) { 34 | if (adminRequest) { 35 | return restClient.put('/carts/' + cartId + '/coupons/' + coupon); 36 | } else { 37 | if (customerToken && isNumeric(cartId)) { 38 | return restClient.put('/carts/mine/coupons/' + coupon, null, customerToken); 39 | } else 40 | { 41 | return restClient.put('/guest-carts/' + cartId + '/coupons/' + coupon); 42 | } 43 | } 44 | } 45 | module.deleteCoupon = function (customerToken, cartId, adminRequest = false) { 46 | if (adminRequest) { 47 | return restClient.delete('/carts/' + cartId + '/coupons'); 48 | } else { 49 | if (customerToken && isNumeric(cartId)) { 50 | return restClient.delete('/carts/mine/coupons', customerToken); 51 | } else 52 | { 53 | return restClient.delete('/guest-carts/' + cartId + '/coupons'); 54 | } 55 | } 56 | } 57 | module.getCoupon = function (customerToken, cartId, adminRequest = false) { 58 | if (adminRequest) { 59 | return restClient.get('/carts/' + cartId + '/coupons'); 60 | } else { 61 | if (customerToken && isNumeric(cartId)) { 62 | return restClient.get('/carts/mine/coupons', customerToken); 63 | } else 64 | { 65 | return restClient.get('/guest-carts/' + cartId + '/coupons'); 66 | } 67 | } 68 | } 69 | module.delete = function (customerToken, cartId, cartItem, adminRequest = false) { 70 | if (adminRequest) { 71 | return restClient.delete('/carts/' + cartId + '/items/' + cartItem.item_id); 72 | } else { 73 | if (customerToken && isNumeric(cartId)) { 74 | return restClient.delete('/carts/mine/items/' + cartItem.item_id, customerToken); 75 | } else 76 | { 77 | return restClient.delete('/guest-carts/' + cartId + '/items/' + cartItem.item_id); 78 | } 79 | } 80 | } 81 | module.pull = function (customerToken, cartId, params, adminRequest = false) { 82 | if (adminRequest) { 83 | return restClient.get('/carts/' + cartId + '/items/'); 84 | } else { 85 | if (customerToken && isNumeric(cartId)) { 86 | return restClient.get('/carts/mine/items', customerToken); 87 | } else 88 | { 89 | return restClient.get('/guest-carts/' + cartId + '/items/'); 90 | } 91 | } 92 | } 93 | module.totals = function (customerToken, cartId, params, adminRequest = false) { 94 | if (adminRequest) { 95 | return restClient.get('/carts/' + cartId + '/totals/'); 96 | } else { 97 | if (customerToken && isNumeric(cartId)) { 98 | return restClient.get('/carts/mine/totals', customerToken); 99 | } else 100 | { 101 | return restClient.get('/guest-carts/' + cartId + '/totals/'); 102 | } 103 | } 104 | } 105 | 106 | module.billingAddress = function (customerToken, cartId, body, adminRequest = false) { 107 | if (adminRequest) { 108 | return restClient.post('/carts/' + cartId + '/billing-address', body); 109 | } else { 110 | if (customerToken && isNumeric(cartId)) { 111 | return restClient.post('/carts/mine/billing-address', body, customerToken); 112 | } else 113 | { 114 | return restClient.post('/guest-carts/' + cartId + '/billing-address', body); 115 | } 116 | } 117 | } 118 | 119 | module.shippingInformation = function (customerToken, cartId, body, adminRequest = false) { 120 | if (adminRequest) { 121 | return restClient.post('/carts/' + cartId + '/shipping-information', body); 122 | } else { 123 | if (customerToken && isNumeric(cartId)) { 124 | return restClient.post('/carts/mine/shipping-information', body, customerToken); 125 | } else 126 | { 127 | return restClient.post('/guest-carts/' + cartId + '/shipping-information', body); 128 | } 129 | } 130 | } 131 | 132 | module.order = function (customerToken, cartId, body, adminRequest = false) { 133 | if (adminRequest) { 134 | return restClient.put('/carts/' + cartId + '/order', body); 135 | } else { 136 | if (customerToken && isNumeric(cartId)) { 137 | return restClient.put('/carts/mine/order', body, customerToken); 138 | } else 139 | { 140 | return restClient.put('/guest-carts/' + cartId + '/order', body); 141 | } 142 | } 143 | } 144 | 145 | module.paymentInformationAndOrder = function (customerToken, cartId, body, adminRequest = false, headers = {}) { 146 | if (adminRequest) { 147 | return restClient.post('/carts/' + cartId + '/payment-information', body, '', headers); 148 | } else { 149 | if (customerToken && isNumeric(cartId)) { 150 | return restClient.post('/carts/mine/payment-information', body, customerToken, headers); 151 | } else 152 | { 153 | return restClient.post('/guest-carts/' + cartId + '/payment-information', body, '', headers); 154 | } 155 | } 156 | } 157 | 158 | module.assign = function (cartId, userId, storeId = 0) { 159 | return restClient.put('/guest-carts/' + cartId, 160 | { 161 | customerId: userId, 162 | storeId: storeId 163 | } 164 | ) 165 | } 166 | 167 | module.shippingMethods = function (customerToken, cartId, address) { 168 | if (customerToken && isNumeric(cartId)) { 169 | return restClient.post('/carts/mine/estimate-shipping-methods', { address: address }, customerToken) 170 | } else 171 | { 172 | return restClient.post('/guest-carts/' + cartId + '/estimate-shipping-methods', { address: address }) 173 | } 174 | } 175 | 176 | module.paymentMethods = function (customerToken, cartId) { 177 | if (customerToken && isNumeric(cartId)) { 178 | return restClient.get('/carts/mine/payment-methods', customerToken) 179 | } else 180 | { 181 | return restClient.get('/guest-carts/' + cartId + '/payment-methods') 182 | } 183 | } 184 | 185 | module.collectTotals = function (customerToken, cartId, shippingMethod) { 186 | if (customerToken && isNumeric(cartId)) { 187 | return restClient.put('/carts/mine/collect-totals', shippingMethod, customerToken) 188 | } else 189 | { 190 | return restClient.put('/guest-carts/' + cartId + '/collect-totals', shippingMethod) 191 | } 192 | } 193 | 194 | return module; 195 | } 196 | -------------------------------------------------------------------------------- /lib/categories.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function () { 7 | return restClient.get('/categories'); 8 | } 9 | 10 | module.create = function (categoryAttributes) { 11 | return restClient.post('/categories', categoryAttributes); 12 | } 13 | 14 | module.update = function (categoryId, categoryAttributes) { 15 | var endpointUrl = util.format('/categories/%d', categoryId); 16 | return restClient.put(endpointUrl, categoryAttributes); 17 | } 18 | 19 | module.delete = function (categoryId) { 20 | var endpointUrl = util.format('/categories/%d', categoryId); 21 | return restClient.delete(endpointUrl); 22 | } 23 | 24 | return module; 25 | } 26 | -------------------------------------------------------------------------------- /lib/category_products.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function (categoryId) { 7 | var endpointUrl = util.format('/categories/%d/products', categoryId); 8 | return restClient.get(endpointUrl); 9 | } 10 | 11 | 12 | return module; 13 | } 14 | -------------------------------------------------------------------------------- /lib/configurable_children.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function (sku) { 7 | var endpointUrl = util.format('/configurable-products/%s/children', encodeURIComponent(sku)); 8 | return restClient.get(endpointUrl); 9 | } 10 | 11 | 12 | return module; 13 | } 14 | -------------------------------------------------------------------------------- /lib/configurable_options.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function (sku) { 7 | var endpointUrl = util.format('/configurable-products/%s/options/all', encodeURIComponent(sku)); 8 | return restClient.get(endpointUrl); 9 | } 10 | 11 | 12 | return module; 13 | } 14 | -------------------------------------------------------------------------------- /lib/customers.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | module.exports = function (restClient) { 3 | var module = {}; 4 | 5 | module.create = function (customerData) { 6 | return restClient.post('/customers', customerData); 7 | } 8 | 9 | module.token = function (loginData) { 10 | 11 | return restClient.consumerToken(loginData) 12 | } 13 | 14 | module.me = function (requestToken) { 15 | 16 | return restClient.get('/customers/me', requestToken) 17 | } 18 | module.orderHistory = function (requestToken, pageSize = 20, currentPage = 1) { 19 | 20 | return restClient.get('/customers/me', requestToken).then((result) => { 21 | var query = 'searchCriteria=&searchCriteria[filterGroups][0][filters][0][field]=customer_id&' + 22 | 'searchCriteria[filterGroups][0][filters][0][value]=' + result.id + '&' + 23 | 'searchCriteria[filterGroups][0][filters][0][condition_type]=eq&' + 24 | 'searchCriteria[pageSize]=' + pageSize + '&searchCriteria[currentPage]=' + currentPage + '&' + 25 | 'searchCriteria[sortOrders][0][field]=entity_id&searchCriteria[sortOrders][0][direction]=desc'; 26 | var endpointUrl = util.format('/orders?%s', query); 27 | return restClient.get(endpointUrl); 28 | }) 29 | } 30 | module.resetPassword = function (emailData) { 31 | 32 | return restClient.put('/customers/password', emailData) 33 | } 34 | 35 | module.resetPasswordUsingResetToken = function (resetPasswordData) { 36 | 37 | return restClient.post('/customers/resetPassword', resetPasswordData) 38 | } 39 | 40 | module.update = function (userData) { 41 | return restClient.put('/customers/me', userData.body, userData.token) 42 | } 43 | 44 | module.changePassword = function (passwordData) { 45 | return restClient.put('/customers/me/password', passwordData.body, passwordData.token) 46 | } 47 | 48 | return module; 49 | } 50 | -------------------------------------------------------------------------------- /lib/directory.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.countries = function () { 7 | var endpointUrl = util.format('/directory/countries'); 8 | return restClient.get(endpointUrl); 9 | } 10 | 11 | module.currency = function () { 12 | var endpointUrl = util.format('/directory/currency'); 13 | return restClient.get(endpointUrl); 14 | } 15 | return module; 16 | } 17 | -------------------------------------------------------------------------------- /lib/log.js: -------------------------------------------------------------------------------- 1 | var winston = require('winston'); 2 | 3 | winston.emitErrs = true; 4 | 5 | var logger = new winston.Logger({ 6 | transports: [ 7 | new winston.transports.Console({ 8 | level: 'debug', 9 | handleExceptions: true, 10 | json: false, 11 | colorize: true 12 | }) 13 | ], 14 | exitOnError: false 15 | }); 16 | 17 | logger.info('Winston logging library initialized.'); 18 | 19 | module.exports = logger; 20 | -------------------------------------------------------------------------------- /lib/orders.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function (restClient) { 3 | var module = {}; 4 | 5 | /** 6 | * 7 | * @see https://devdocs.magento.com/guides/v2.3/rest/retrieve-filtered-responses.html 8 | * @see salesOrderRepositoryV1: GET /V1/orders/{id} 9 | * 10 | * @param oderId 11 | * @returns {Promise<{increment_id: String}>} 12 | */ 13 | module.incrementIdById = function (oderId) { 14 | return restClient.get('/orders/' + oderId + '?fields=increment_id'); 15 | }; 16 | 17 | module.pending = function () { 18 | return restClient.get('/orders/pending'); 19 | }; 20 | module.searchOrderByOrderId = function (orderId) { 21 | return restClient.get('/orders/?searchCriteria[filter_groups][0][filters][0][field]=entity_id&' + 22 | 'searchCriteria[filter_groups][0][filters][0][value]='+orderId+'&' + 23 | 'searchCriteria[filter_groups][0][filters][0][condition_type]=eq'); 24 | }; 25 | module.searchOrderByIncrementId = function (increment_id) { 26 | return restClient.get('/orders/?searchCriteria[filter_groups][0][filters][0][field]=increment_id&' + 27 | 'searchCriteria[filter_groups][0][filters][0][value]='+increment_id+'&' + 28 | 'searchCriteria[filter_groups][0][filters][0][condition_type]=eq'); 29 | }; 30 | 31 | 32 | return module; 33 | } 34 | -------------------------------------------------------------------------------- /lib/product_media.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function (productSku) { 7 | var endpointUrl = util.format('/products/%s/media', productSku); 8 | return restClient.get(endpointUrl); 9 | } 10 | 11 | module.get = function (productSku, mediaId) { 12 | var endpointUrl = util.format('/products/%s/media/%d', encodeURIComponent(productSku), mediaId); 13 | return restClient.get(endpointUrl); 14 | } 15 | 16 | module.create = function (productSku, productMediaAttributes) { 17 | var endpointUrl = util.format('/products/%s/media', encodeURIComponent(productSku)); 18 | return restClient.post(endpointUrl, productMediaAttributes); 19 | } 20 | 21 | module.update = function (productSku, mediaId, productMediaAttributes) { 22 | var endpointUrl = util.format('/products/%s/media/%d', encodeURIComponent(productSku), mediaId); 23 | return restClient.put(endpointUrl, productMediaAttributes); 24 | } 25 | 26 | module.delete = function (productSku, mediaId) { 27 | var endpointUrl = util.format('/products/%s/media/%d', encodeURIComponent(productSku), mediaId); 28 | return restClient.delete(endpointUrl); 29 | } 30 | 31 | return module; 32 | } 33 | -------------------------------------------------------------------------------- /lib/products.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function (searchCriteria) { 7 | var query = 'searchCriteria=' + searchCriteria; 8 | var endpointUrl = util.format('/products?%s', query); 9 | return restClient.get(endpointUrl); 10 | } 11 | module.renderList = function (searchCriteria, currencyCode = 'USD', storeId = 1) { 12 | var query = 'searchCriteria=' + searchCriteria; 13 | var endpointUrl = util.format('/products-render-info?%s&storeId=%d¤cyCode=' + encodeURIComponent(currencyCode), query, storeId); 14 | return restClient.get(endpointUrl); 15 | } 16 | module.create = function (productAttributes) { 17 | return restClient.post('/products', productAttributes); 18 | } 19 | 20 | module.update = function (productSku, productAttributes) { 21 | var endpointUrl = util.format('/products/%s', encodeURIComponent(productSku)); 22 | return restClient.put(endpointUrl, productAttributes); 23 | } 24 | 25 | module.delete = function (productSku) { 26 | var endpointUrl = util.format('/products/%s', encodeURIComponent(productSku)); 27 | return restClient.delete(endpointUrl); 28 | } 29 | 30 | return module; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /lib/rest_client.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var OAuth = require('oauth-1.0a'); 4 | var request = require('request'); 5 | var humps = require('humps'); 6 | var sprintf = require('util').format; 7 | 8 | var logger = require('./log'); 9 | 10 | module.exports.RestClient = function (options) { 11 | var instance = {}; 12 | 13 | var servelrUrl = options.url; 14 | var apiVersion = options.version; 15 | var oauth = OAuth({ 16 | consumer: { 17 | public: options.consumerKey, 18 | secret: options.consumerSecret 19 | }, 20 | signature_method: options.signatureMethod || 'HMAC-SHA1' 21 | }); 22 | var token = { 23 | public: options.accessToken, 24 | secret: options.accessTokenSecret 25 | }; 26 | 27 | function apiCall(request_data, request_token = '', customHeaders = {}) { 28 | /* eslint no-undef: off*/ 29 | return new Promise(function (resolve, reject) { 30 | request({ 31 | url: request_data.url, 32 | method: request_data.method, 33 | headers: { 34 | ...(request_token 35 | ? { 'Authorization': 'Bearer ' + request_token } 36 | : oauth.toHeader(oauth.authorize(request_data, token)) 37 | ), 38 | ...customHeaders 39 | }, 40 | json: true, 41 | body: request_data.body, 42 | }, function (error, response, body) { 43 | if (error) { 44 | logger.error('Error occured: ' + error); 45 | reject(error); 46 | return; 47 | } else if (!httpCallSucceeded(response)) { 48 | var errorMessage = 'HTTP ERROR ' + response.code; 49 | if(body && body.hasOwnProperty('message') ) 50 | errorMessage = errorString(body.message, body.hasOwnProperty('parameters') ? body.parameters : {}); 51 | 52 | logger.error('API call failed: ' + errorMessage); 53 | reject({ 54 | errorMessage, 55 | code: response.statusCode, 56 | toString: () => { 57 | return this.errorMessage 58 | } 59 | }); 60 | } 61 | // var bodyCamelized = humps.camelizeKeys(body); 62 | // resolve(bodyCamelized); 63 | resolve(body); 64 | }); 65 | }); 66 | } 67 | 68 | instance.consumerToken = function (login_data) { 69 | return apiCall({ 70 | url: createUrl('/integration/customer/token'), 71 | method: 'POST', 72 | body: login_data 73 | }) 74 | } 75 | 76 | function httpCallSucceeded(response) { 77 | return response.statusCode >= 200 && response.statusCode < 300; 78 | } 79 | 80 | function errorString(message, parameters) { 81 | if (parameters === null) { 82 | return message; 83 | } 84 | if (parameters instanceof Array) { 85 | for (var i = 0; i < parameters.length; i++) { 86 | var parameterPlaceholder = '%' + (i + 1).toString(); 87 | message = message.replace(parameterPlaceholder, parameters[i]); 88 | } 89 | } else if (parameters instanceof Object) { 90 | for (var key in parameters) { 91 | var parameterPlaceholder = '%' + key; 92 | message = message.replace(parameterPlaceholder, parameters[key]); 93 | } 94 | } 95 | 96 | return message; 97 | } 98 | 99 | instance.get = function (resourceUrl, request_token = '') { 100 | var request_data = { 101 | url: createUrl(resourceUrl), 102 | method: 'GET' 103 | }; 104 | return apiCall(request_data, request_token); 105 | } 106 | 107 | function createUrl(resourceUrl) { 108 | return servelrUrl + '/' + apiVersion + resourceUrl; 109 | } 110 | 111 | instance.post = function (resourceUrl, data, request_token = '', customHeaders = {}) { 112 | var request_data = { 113 | url: createUrl(resourceUrl), 114 | method: 'POST', 115 | body: data 116 | }; 117 | return apiCall(request_data, request_token, customHeaders); 118 | } 119 | 120 | instance.put = function (resourceUrl, data, request_token = '') { 121 | var request_data = { 122 | url: createUrl(resourceUrl), 123 | method: 'PUT', 124 | body: data 125 | }; 126 | return apiCall(request_data, request_token); 127 | } 128 | 129 | instance.delete = function (resourceUrl, request_token = '') { 130 | var request_data = { 131 | url: createUrl(resourceUrl), 132 | method: 'DELETE' 133 | }; 134 | return apiCall(request_data, request_token); 135 | } 136 | 137 | return instance; 138 | } 139 | -------------------------------------------------------------------------------- /lib/reviews.js: -------------------------------------------------------------------------------- 1 | const util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.getByProductSku = function (sku) { 7 | const endpointUrl = util.format('/products/%s/reviews', encodeURIComponent(sku)); 8 | return restClient.get(endpointUrl); 9 | }; 10 | 11 | module.list = function(searchCriteria) { 12 | const query = 'searchCriteria=' + searchCriteria; 13 | const endpointUrl = util.format('/reviews/?%s', query); 14 | return restClient.get(endpointUrl); 15 | }; 16 | 17 | module.create = function (reviewData) { 18 | return restClient.post('/reviews', {review: reviewData}) 19 | } 20 | 21 | module.delete = function (reviewId) { 22 | var endpointUrl = util.format('/reviews/%d', reviewId); 23 | return restClient.delete(endpointUrl); 24 | } 25 | 26 | return module; 27 | }; 28 | -------------------------------------------------------------------------------- /lib/stock_items.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function (sku) { 7 | var endpointUrl = util.format('/stockItems/%s', encodeURIComponent(sku)); 8 | return restClient.get(endpointUrl); 9 | } 10 | 11 | // MSI 12 | module.getSalableQty = function (sku, stockId) { 13 | var endpointUrl = util.format( 14 | '/inventory/get-product-salable-quantity/%s/%d', 15 | encodeURIComponent(sku), 16 | encodeURIComponent(stockId) 17 | ); 18 | return restClient.get(endpointUrl); 19 | } 20 | 21 | // MSI 22 | module.isSalable = function (sku, stockId) { 23 | var endpointUrl = util.format( 24 | '/inventory/is-product-salable/%s/%d', 25 | encodeURIComponent(sku), 26 | encodeURIComponent(stockId) 27 | ); 28 | return restClient.get(endpointUrl); 29 | } 30 | 31 | return module; 32 | } 33 | -------------------------------------------------------------------------------- /lib/tax_rates.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function (rateId) { 7 | var endpointUrl = util.format('/taxRates/%d', rateId); 8 | return restClient.get(endpointUrl); 9 | } 10 | 11 | module.create = function (rateAttributes) { 12 | return restClient.post('/taxRates', rateAttributes); 13 | } 14 | 15 | module.update = function (rateId, rateAttributes) { 16 | var endpointUrl = util.format('/taxRates/%d', rateId); 17 | return restClient.put(endpointUrl, rateAttributes); 18 | } 19 | 20 | module.delete = function (rateId) { 21 | var endpointUrl = util.format('/taxRates/%d', rateId); 22 | return restClient.delete(endpointUrl); 23 | } 24 | 25 | return module; 26 | } 27 | -------------------------------------------------------------------------------- /lib/tax_rules.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | 3 | module.exports = function (restClient) { 4 | var module = {}; 5 | 6 | module.list = function (searchCriteria) { 7 | var query = 'searchCriteria=' + searchCriteria; 8 | var endpointUrl = util.format('/taxRules/search?%s', query); 9 | return restClient.get(endpointUrl); 10 | } 11 | 12 | module.create = function (ruleAttributes) { 13 | return restClient.post('/taxRules', ruleAttributes); 14 | } 15 | 16 | module.update = function (ruleId, ruleAttributes) { 17 | var endpointUrl = util.format('/taxRules/%d', ruleId); 18 | return restClient.put(endpointUrl, ruleAttributes); 19 | } 20 | 21 | module.delete = function (ruleId) { 22 | var endpointUrl = util.format('/taxRules/%d', ruleId); 23 | return restClient.delete(endpointUrl); 24 | } 25 | 26 | return module; 27 | } 28 | -------------------------------------------------------------------------------- /magento2-rest-client.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_from": "magento2-rest-client@0.0.2", 3 | "_id": "magento2-rest-client@0.0.2", 4 | "_inBundle": false, 5 | "_integrity": "sha1-Km7yMMiBKahoC2Pq03k+p+mb9qQ=", 6 | "_location": "/magento2-rest-client", 7 | "_phantomChildren": {}, 8 | "_requested": { 9 | "type": "version", 10 | "registry": true, 11 | "raw": "magento2-rest-client@0.0.2", 12 | "name": "magento2-rest-client", 13 | "escapedName": "magento2-rest-client", 14 | "rawSpec": "0.0.2", 15 | "saveSpec": null, 16 | "fetchSpec": "0.0.2" 17 | }, 18 | "_requiredBy": [ 19 | "/" 20 | ], 21 | "_resolved": "https://registry.npmjs.org/magento2-rest-client/-/magento2-rest-client-0.0.2.tgz", 22 | "_shasum": "2a6ef230c88129a8680b63ead3793ea7e99bf6a4", 23 | "_spec": "magento2-rest-client@0.0.2", 24 | "_where": "/Users/pkarwatka/Documents/_PROJEKTY/mage2nosql/src", 25 | "author": { 26 | "name": "Marko Novak", 27 | "email": "nouvak@gmail.com" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/nouvak/magento2-rest-client/issues" 31 | }, 32 | "bundleDependencies": false, 33 | "dependencies": { 34 | "humps": "^1.1.0", 35 | "oauth-1.0a": "^1.0.1", 36 | "request": "^2.72.0", 37 | "winston": "^2.2.0" 38 | }, 39 | "deprecated": false, 40 | "description": "REST client for accessing Magento 2 functionality.", 41 | "devDependencies": { 42 | "chai": "^3.5.0", 43 | "mocha": "^2.4.5" 44 | }, 45 | "directories": { 46 | "lib": "./lib" 47 | }, 48 | "homepage": "https://github.com/nouvak/magento2-rest-client#readme", 49 | "keywords": [ 50 | "magento2", 51 | "REST", 52 | "API" 53 | ], 54 | "license": "MIT", 55 | "main": "index.js", 56 | "name": "magento2-rest-client", 57 | "repository": { 58 | "type": "git", 59 | "url": "git+https://github.com/nouvak/magento2-rest-client.git" 60 | }, 61 | "scripts": { 62 | "test": "test" 63 | }, 64 | "version": "0.0.14" 65 | } 66 | -------------------------------------------------------------------------------- /test/integration/categories.integration.test.js: -------------------------------------------------------------------------------- 1 | var chai = require('chai'); 2 | var credentials = require('../config'); 3 | var assert = chai.assert; 4 | 5 | var Magento2Client = require('../../index').Magento2Client; 6 | 7 | suite('categories tests', function () { 8 | var client; 9 | 10 | before(function() { 11 | client = Magento2Client(credentials); 12 | }); 13 | 14 | test('list categories test', function (done) { 15 | client.categories.list() 16 | .then(function (categories) { 17 | assert.equal(categories.parentId, 1); 18 | }) 19 | .then(done, done); 20 | }); 21 | 22 | test('create category test', function (done) { 23 | var newCategory = { 24 | category: { 25 | parentId: 3, 26 | name: 'Category from integration test', 27 | isActive: true, 28 | includeInMenu: true, 29 | } 30 | }; 31 | client.categories.create(newCategory) 32 | .then(function (result) { 33 | assert.equal(result.parentId, 3); 34 | }) 35 | .then(done, done); 36 | }); 37 | 38 | test('update category test', function (done) { 39 | var categoryUpdate = { 40 | category: { 41 | parentId: 3, 42 | name: 'Podkategorija 1 updated', 43 | isActive: true, 44 | includeInMenu: true, 45 | } 46 | }; 47 | client.categories.update(4, categoryUpdate) 48 | .then(function (result) { 49 | assert.equal(result.parentId, 3); 50 | }) 51 | .then(done, done); 52 | }); 53 | 54 | test('delete category test', function (done) { 55 | client.categories.delete(23) 56 | .then(function (result) { 57 | assert.isTrue(result); 58 | }) 59 | .then(done, done); 60 | }) 61 | }); 62 | -------------------------------------------------------------------------------- /test/integration/product_media.integration.test.js: -------------------------------------------------------------------------------- 1 | var chai = require('chai'); 2 | var credentials = require('../config'); 3 | var assert = chai.assert; 4 | 5 | var Magento2Client = require('../../index').Magento2Client; 6 | 7 | suite('products media tests', function () { 8 | var client; 9 | 10 | before(function () { 11 | client = Magento2Client(credentials); 12 | }); 13 | 14 | test('list product media test', function (done) { 15 | client.productMedia.list('test123') 16 | .then(function (productMedia) { 17 | assert.isTrue(productMedia.length > 0); 18 | }) 19 | .then(done, done); 20 | }); 21 | 22 | test('get product media test', function (done) { 23 | client.productMedia.get('test123', 15) 24 | .then(function (productMedia) { 25 | assert.isNotNull(productMedia); 26 | }) 27 | .then(done, done); 28 | }); 29 | 30 | test('create product media test', function (done) { 31 | var newProductMedia = { 32 | 'entry': { 33 | 'media_type': 'image', 34 | 'label': 'Image', 35 | 'position': 1, 36 | 'disabled': false, 37 | 'types': [ 38 | 'image', 39 | 'small_image', 40 | 'thumbnail' 41 | ], 42 | 'file': '/m/b/mb01-blue-0.png', 43 | 'content': { 44 | 'base64EncodedData': 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWtJREFUeNpi/P//P8NgBkwMgxyMOnDUgTDAyMhIDNYF4vNA/B+IDwCxHLoakgEoFxODiQRXQUYi4e3k2gfDjMRajsP3zED8F8pmA+JvUDEYeArEMugOpFcanA/Ef6A0CPwC4uNoag5SnAjJjGI2tKhkg4rLAfFGIH4IxEuBWIjSKKYkDfZCHddLiwChVhokK8YGohwEZYy3aBmEKmDEhOCgreomo+VmZHxsMEQxIc2MAx3FO/DI3RxMmQTZkI9ALDCaSUYdOOrAIeRAPzQ+PxCHUM2FFDb5paGNBPRa5C20bUhxc4sSB4JaLnvxVHWHsbVu6OnACjyOg+HqgXKgGRD/JMKBoD6LDb0dyAPE94hwHAw/hGYcujlwEQmOg+EV9HJgLBmOg+FMWjsQVKR8psCBoDSrQqoDSSmoG6Hpj1wA6ju30LI9+BBX4UsC+Ai0T4BWVd1EIL5PgeO+APECmoXgaGtm1IE0AgABBgAJAICuV8dAUAAAAABJRU5ErkJggg==', 45 | 'type': 'image/png', 46 | 'name': 'new_image.png' 47 | } 48 | } 49 | }; 50 | client.productMedia.create('test123', newProductMedia) 51 | .then(function (result) { 52 | assert.isNotNull(result); 53 | }) 54 | .then(done, done); 55 | }); 56 | 57 | test('update product test', function (done) { 58 | var productMediaUpdate = { 59 | 'entry': { 60 | 'id': 15, 61 | 'label': 'Image updated', 62 | } 63 | }; 64 | client.productMedia.update('test123', 15, productMediaUpdate) 65 | .then(function (result) { 66 | assert.isNotNull(result); 67 | }) 68 | .then(done, done); 69 | }); 70 | 71 | test('delete product test', function (done) { 72 | client.productMedia.delete('test123', 10) 73 | .then(function (result) { 74 | assert.isTrue(result); 75 | }) 76 | .then(done, done); 77 | }) 78 | }); 79 | 80 | -------------------------------------------------------------------------------- /test/integration/products.integration.test.js: -------------------------------------------------------------------------------- 1 | var chai = require('chai'); 2 | var credentials = require('../config'); 3 | var assert = chai.assert; 4 | 5 | var Magento2Client = require('../../index').Magento2Client; 6 | 7 | suite('products tests', function () { 8 | var client; 9 | 10 | before(function() { 11 | client = Magento2Client(credentials); 12 | }); 13 | 14 | test('list products test', function (done) { 15 | client.products.list('Test') 16 | .then(function (products) { 17 | assert.isTrue(products.totalCount > 0); 18 | }) 19 | .then(done, done); 20 | }); 21 | 22 | test('create product test', function (done) { 23 | var newProduct = { 24 | product: { 25 | 'sku': 'test123', 26 | 'name': 'Integration test product', 27 | 'typeId': 'simple', 28 | 'price': 12.3, 29 | 'attributeSetId': 4, 30 | 'status': 1, 31 | 'visibility': 4, 32 | } 33 | }; 34 | client.products.create(newProduct) 35 | .then(function (result) { 36 | assert.equal(result.name, 'Integration test product'); 37 | }) 38 | .then(done, done); 39 | }); 40 | 41 | test('update product test', function (done) { 42 | var productUpdate = { 43 | product: { 44 | 'sku': 'test123', 45 | 'name': 'Integration test product updated', 46 | 'typeId': 'simple', 47 | 'price': 12.3, 48 | 'attributeSetId': 4, 49 | 'status': 1, 50 | 'visibility': 4, 51 | } 52 | }; 53 | client.products.update('test123', productUpdate) 54 | .then(function (result) { 55 | assert.equal(result.name, 'Integration test product updated'); 56 | }) 57 | .then(done, done); 58 | }); 59 | 60 | test('delete product test', function (done) { 61 | client.products.delete(23) 62 | .then(function (result) { 63 | assert.isTrue(result); 64 | }) 65 | .then(done, done); 66 | }) 67 | }); 68 | 69 | --------------------------------------------------------------------------------