Socket
Socket
Sign inDemoInstall

ebay-api

Package Overview
Dependencies
6
Maintainers
1
Versions
73
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.0-alpha to 1.0.0

.travis.yml

48

examples/paginated.js

@@ -6,31 +6,28 @@ // example paginated request to FindingService:findItemsAdvanced

var params = {};
var params = {
categoryId: [ "47123", "14948" ], // Electronics & Gadgets
params.categoryId = [ "47123", "14948" ]; // Electronics & Gadgets
// include SellerInfo in response
outputSelector: [ 'SellerInfo' ],
// include SellerInfo in response
params.outputSelector = [ 'SellerInfo' ];
//// for affiliate links (see https://www.x.com/developers/ebay/use-cases/affiliate-tracking)
affiliate: {
trackingID: '1234567890', // CAMPAIGN ID
networkId: '9', // "If you are registered with eBay Partner Network, the networkId is 9"
customId: '1' // arbitrary, to differentiate sub-campaigns
},
//// for affiliate links (see https://www.x.com/developers/ebay/use-cases/affiliate-tracking)
// params['affiliate.trackingId'] = '1234567890'; // CAMPAIGN ID
// params['affiliate.networkId'] = '9'; // "If you are registered with eBay Partner Network, the networkId is 9"
// params['affiliate.customId'] = '1'; // arbitrary, to differentiate sub-campaigns
itemFilter: [
// (most of these can be 1 item or array of multiple items, depending on the service)
{name: "ExcludeCategory", value: "14998"}, // no Vintage Electronics
{name: "ListingType", value: "Auction"},
var filters = {};
// example of 2-part filter
{name: 'MinPrice', value: '20', paramName: 'Currency', paramValue: 'USD'},
{name: 'MaxPrice', value: '300', paramName: 'Currency', paramValue: 'USD'}
]
};
filters.itemFilter = [
// (most of these can be 1 item or array of multiple items, depending on the service)
new ebay.ItemFilter("ExcludeCategory", ["14998"]), // no Vintage Electronics
// new ebay.ItemFilter("ExcludeSeller", ["somebadseller"]),
new ebay.ItemFilter("ListingType", ["Auction"]),
new ebay.ItemFilter('MinPrice', '20', 'Currency', 'USD'),
new ebay.ItemFilter('MaxPrice', '300', 'Currency', 'USD'), // example of 2-part filter
];
// run it (paginated)
var pages = 2,
perPage = 3; // max 100x100 (10k items)
ebay.paginateGetRequest({
ebay.paginatedRequest({
serviceName: 'Finding',

@@ -40,5 +37,4 @@ opType: 'findItemsAdvanced',

params: params,
filters: filters,
pages: pages,
perPage: perPage,
pages: 2,
perPage: 3, // max 100x100 (10k items)
parser: ebay.parseResponse

@@ -45,0 +41,0 @@ },

@@ -5,6 +5,4 @@ // eBay API client for Node.js

exports.paginateGetRequest = require('./lib/pagination').paginateGetRequest;
exports.paginatedRequest = require('./lib/pagination').paginatedRequest;
exports.ItemFilter = require('./lib/filters').ItemFilter;
exports.parseResponse = require('./lib/parser').parseResponse;

@@ -8,16 +8,3 @@ var

default params per service type.
for GET requests these go into URL. for POST requests these go into headers.
options differ by service, see below.
@option appId
@option opType
@option version
@option globalId ?
@option siteId ?
@option devName
@option cert
...
@param {object} options: request context. see `xmlRequest()` docs, and code below.
*/

@@ -52,10 +39,9 @@ exports.getDefaultHeaders = function(options) {

return {
'SERVICE-NAME': options.serviceName,
'CONSUMER-ID': options.appId ? options.appId : null,
// based on response data
'X-EBAY-SOA-SERVICE-NAME': 'MerchandisingService',
'X-EBAY-SOA-OPERATION-NAME': options.opType,
'EBAY-SOA-CONSUMER-ID': options.appId ? options.appId : null,
'SERVICE-VERSION': options.version ? options.version : '1.5.0',
'OPERATION-NAME': options.opType,
'GLOBAL-ID': options.globalId ? options.globalId : 'EBAY-US',
'RESPONSE-DATA-FORMAT': 'XML',
'REST-PAYLOAD': null // (not sure what this does)
'X-EBAY-SOA-REQUEST-DATA-FORMAT': 'XML',
//'RESPONSE-DATA-FORMAT': 'XML',
//'REST-PAYLOAD': null // (not sure what this does)
};

@@ -62,0 +48,0 @@

@@ -9,3 +9,3 @@ var

// PAGINATE multiple GET/JSON requests in parallel (max 100 per page, 100 pages = 10k items)
exports.paginateGetRequest = function(options, callback) {
exports.paginatedRequest = function(options, callback) {
throw new Error("TODO re-implement/refactor me!");

@@ -18,3 +18,2 @@

//options.params = options.params || {};
//options.filters = options.filters || {};
//options.reqOptions = options.reqOptions || {};

@@ -21,0 +20,0 @@ //options.pages = options.pages || 2;

@@ -148,2 +148,4 @@ var

var flatten = exports.flatten;
data = flatten(data, 1); // top level first

@@ -188,2 +190,6 @@ debug('flattened', data);

if (data.paginationOutput) {
data.paginationOutput = flatten(data.paginationOutput);
}
//

@@ -194,33 +200,3 @@ // PER-OP PARSING

//var items = [];
//if (typeof data.Item !== 'undefined') { // e.g. for Shopping::GetSingleItem
// items = [ data.Item ]; // preserve array for standardization (?)
//}
//
//else if (typeof data.searchResult !== 'undefined') { // e.g. for FindingService
// // reduce in steps so successful-but-empty responses don't throw error
// if (!_.isEmpty(data.searchResult)) {
// data = _(data.searchResult).first();
// if (typeof data !== 'undefined') {
// if (typeof data.item !== 'undefined') {
// items = data.item;
// }
// }
// }
//}
//else if (typeof data.itemRecommendations !== 'undefined') {
// if (typeof data.itemRecommendations !== 'undefined') {
// if (typeof data.itemRecommendations.item !== 'undefined') {
// items = _.isArray(data.itemRecommendations.item) ? data.itemRecommendations.item : [];
// }
// }
//}
//
//// recursively flatten 1-level arrays and "@key:__VALUE__" pairs
//items = _(items).map(function(item) {
// return flatten(item);
//});
return data;
};

@@ -6,111 +6,41 @@ var

// [internal] convert params hash to url string.
// some items may be arrays, use key(0)..(n)
// param usage:
// - use null values for plain params
// - use arrays for repeating keys
function buildUrlParams(obj, prefix) {
var i, k, keys, str, _fn, _i, _j, _len, _len1;
str = [];
if (typeof prefix === "undefined") {
prefix = "";
}
if (obj === null) { return prefix; }
if (obj.constructor.toString().match(/^function\sarray/i)) {
_fn = function(o) {
return str.push(buildUrlParams(o, prefix + "(" + i + ")"));
};
for (i = _i = 0, _len = obj.length; _i < _len; i = ++_i) {
k = obj[i];
_fn(k);
}
} else if (obj.constructor.toString().match(/^function\sobject/i)) {
if (prefix !== "") {
prefix += ".";
}
keys = Object.keys(obj);
for (i = _j = 0, _len1 = keys.length; _j < _len1; i = ++_j) {
k = keys[i];
str.push(buildUrlParams(obj[k], prefix + k));
}
} else {
str.push(prefix + "=" + obj);
debug(prefix + " = " + obj);
}
return str.join("&");
}
// [internal] convert a filters array to a url string
// adapted from client-side JS example in ebay docs
function buildFilters(filterType, filters) {
var urlFilter = '';
_(filters).each(function eachItemFilter(filter, filterInd) {
// each parameter in each item filter
_(filter).each(function eachItemParam(paramVal, paramKey) {
// Check to see if the paramter has a value (some don't)
if (paramVal !== "") {
// multi-value param
if (_.isArray(paramVal)) {
_(paramVal).each(function eachSubFilter(paramSubVal, paramSubIndex) {
urlFilter += '&' + filterType + '(' + filterInd + ').' + paramKey + '(' + paramSubIndex + ')=' + paramSubVal;
});
}
// single-value param
else {
urlFilter += '&' + filterType + '(' + filterInd + ').' + paramKey + '=' + paramVal;
}
}
});
});
return urlFilter;
}
/*
build URL to API endpoints
set sandbox=true for sandbox, otherwise production
- params is a 1D obj
- filters is an obj of { filterType:[filters] } (where filters is an array of ItemFilter)
params,filters only apply to GET requests; for POST pass in empty {} or null
@TODO does this need `params` or `filters` anymore? -- if everything is XML??
build URL to API endpoints.
@param options: request context (see
*/
exports.buildRequestUrl = function(serviceName, params, filters, sandbox) {
exports.buildRequestUrl = function(options) {
var url;
params = params || {};
filters = filters || {};
sandbox = (typeof sandbox === 'boolean') ? sandbox : false;
options = options || {};
var serviceName = options.serviceName.replace(/Service$/, '');
switch (serviceName) {
case 'Finding':
if (sandbox) {
throw new Error("There is no sandbox environment for the FindingService.");
}
else url = "https://svcs.ebay.com/services/search/FindingService/v1?";
if (options.sandbox) url = 'http://svcs.sandbox.ebay.com/services/search/FindingService/v1';
else url = 'https://svcs.ebay.com/services/search/FindingService/v1';
break;
case 'Product':
if (sandbox) url = "http://svcs.sandbox.ebay.com/services/marketplacecatalog/" + serviceName + "/v1?";
else url = "http://svcs.ebay.com/services/marketplacecatalog/" + serviceName + "/v1?";
if (options.sandbox) url = 'http://svcs.sandbox.ebay.com/services/marketplacecatalog/' + serviceName + '/v1';
else url = 'https://svcs.ebay.com/services/marketplacecatalog/' + serviceName + '/v1';
break;
case 'Shopping':
if (sandbox) url = 'http://open.api.sandbox.ebay.com/shopping?';
else url = "https://open.api.ebay.com/shopping?";
if (options.sandbox) url = 'http://open.api.sandbox.ebay.com/shopping';
else url = "https://open.api.ebay.com/shopping";
break;
case 'Trading': // ...and the other XML APIs
if (sandbox) url = 'https://api.sandbox.ebay.com/ws/api.dll';
case 'Trading':
if (options.sandbox) url = 'https://api.sandbox.ebay.com/ws/api.dll';
else url = 'https://api.ebay.com/ws/api.dll';
break;
// params and filters don't apply to URLs w/ these
return url;
// break;
case 'Merchandising':
if (options.sandbox) url = 'http://svcs.sandbox.ebay.com/MerchandisingService';
else url = "https://svcs.ebay.com/MerchandisingService";
break;
default:
if (sandbox) {
if (options.sandbox) {
throw new Error("Sandbox endpoint for " + serviceName + " service not yet implemented. Please add.");

@@ -121,9 +51,5 @@ }

url += buildUrlParams(params); // no trailing &
// [removed URL params - all XML based now. if need to bring back, look in git history.]
_(filters).each(function(typeFilters, type) {
url += buildFilters(type, typeFilters); // each has leading &
});
return url;
};

@@ -14,16 +14,33 @@ var

// need arrays all the way down... (quirk of xml module).
/**
* handle quirk of 'xml' module:
* need arrays all the way down,
* and objects can only have a single key:value,
* e.g. {k1:v1,k2:v2} need to become [{k1:[v1]}, {k2:[v2]}].
* @see tests in xml-request.test.js.
*/
exports._deepToArray = function _deepToArray(obj) {
var key, value;
if (_.isObject(obj)) {
var key, value, arr = [];
if (_.isArray(obj)) {
// not sure about this: arrays within objects are handled below;
// top level should never be an array;
// but seems ok. change/fix if a scenario comes up that this breaks.
return obj.map(function(value) {
return _deepToArray(value);
});
}
else if (_.isObject(obj)) {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
value = obj[key];
if (_.isArray(value)) { // recurse over array children
obj[key] = value.map(function(subValue) {
return _deepToArray(subValue);
// `{foo: [a,b,c]}` => `[{foo:a},{foo:b},{foo:c}]`
if (_.isArray(value)) {
value.forEach(function(subValue) {
arr.push(_.set({}, key, _deepToArray(subValue)));
});
}
else { // make it an array
obj[key] = [ _deepToArray(value) ];
else {
arr.push(_.set({}, key, _deepToArray(value)));
}

@@ -33,3 +50,6 @@ }

}
return obj;
else {
arr = [obj];
}
return arr;
};

@@ -40,5 +60,3 @@

build XML input for XML requests (POST).
@param {object} options: request context.
@option {object} params: custom input params.
@param {object} options: request context. see `xmlRequest()` docs.
for repeatable fields, use an array value (see below).

@@ -55,20 +73,15 @@ */

if (options.serviceName === 'Finding') {
root.push({'_attr' : {'xmlns' : 'http://www.ebay.com/marketplace/search/v1/services'}});
root.push({'_attr': {'xmlns': 'http://www.ebay.com/marketplace/search/v1/services'}});
}
else {
root.push({'_attr' : {'xmlns' : 'urn:ebay:apis:eBLBaseComponents'}});
root.push({'_attr': {'xmlns': 'urn:ebay:apis:eBLBaseComponents'}});
}
if (options.authToken) {
root.push({ 'RequesterCredentials' : [ { 'eBayAuthToken' : options.authToken } ] });
root.push({ 'RequesterCredentials': [ { 'eBayAuthToken' : options.authToken } ] });
}
params = exports._deepToArray(params);
// concat
root.push.apply(root, exports._deepToArray(params));
_.each(params, function(value, key) { // keys in top object
_.each(params[key], function(value) { // arrays
root.push(_.set({}, key, [value]));
});
});
debug('Converting to XML', data);

@@ -87,4 +100,21 @@

/*
@param {object} @options
@option reqOptions: passed to request
@param {object} @options:
@option {object} reqOptions: passed to request
@option {string} appId
@option {string} opType
@option {string} version
@option {string} devName
@option {string} cert
@option {string} authToken
@option {string} globalId
@option {string} siteId
@option {object} params: this gets converted to an XML body with request parameters.
all filters go in here. use nested objects where appropriate. see the API docs.
...
@param {function} callback: gets response

@@ -104,4 +134,3 @@ */

var reqOptions = _.extend({}, options.reqOptions, {
url: buildRequestUrl(options.serviceName, {}, {}, options.sandbox || false),
// @see note in buildXmlInput() re: nested elements (...??)
url: buildRequestUrl(options),
body: buildXmlInput(options),

@@ -108,0 +137,0 @@ });

{
"name": "ebay-api",
"description": "eBay API Client",
"version": "1.0.0-alpha",
"version": "1.0.0",
"homepage": "https://github.com/newleafdigital/nodejs-ebay-api",

@@ -30,4 +30,4 @@ "author": "Ben Buckman <ben@newleafdigital.com> (http://newleafdigital.com)",

"engines": {
"node": ">= 0.6"
"node": ">= 0.10"
}
}
eBay API client for Node.js
===============
[![Build Status](https://travis-ci.org/benbuckman/nodejs-ebay-api.svg)](https://travis-ci.org/benbuckman/nodejs-ebay-api)
## Intro

@@ -62,4 +64,4 @@

- `params`: (see examples and API documentation)
- `filters`: (see examples and API documentation.) _might no longer work in 1.x: if you're using this, please submit a PR!_
- `reqOptions`: passed to the [request](https://github.com/request/request) module, e.g. for additional `headers`.
- `reqOptions`: passed to the [request](https://github.com/request/request) module,
e.g. for additional `headers`, or `timeout`.
- `parser`: function which takes the response data and extracts items (or other units depending on the query).

@@ -97,2 +99,9 @@ _Module includes a default parser._

## Debugging
This module uses the [debug](https://github.com/visionmedia/debug) module for internal logging.
Run your app (or node REPL) with `DEBUG=ebay* ...` to see output.
## Helpers

@@ -106,2 +115,3 @@

- The structure of the format `{ @key:KEY, __value__:VALUE }` is flattened to its key:value pair.
- Other weird structures (from the API itself, or the XML->JSON conversion) are simplified. _(See the code for details.)_

@@ -112,8 +122,7 @@ Its purpose is to make the data easier to handle in code, and to model/query in MongoDB.

The default parser will `flatten()` the response to a finite depth
(because infinite recursion on an indeterminate response size would cause an unnecessary performance hit).
If you want to flatten further, use this method directly.
### `ItemFilter(name, value, paramName, paramValue)`
A class constructor to simplify creating filters. (See the examples)
### `getLatestApiVersions(callback)`

@@ -120,0 +129,0 @@

@@ -147,3 +147,3 @@ var

describe('`parseResponse`', function() {
// @TODO
it('#TODO')
});

@@ -48,3 +48,3 @@ var

expect(request.post.lastCall.args[0]).to.deep.equal({
url: 'http://open.api.sandbox.ebay.com/shopping?',
url: 'http://open.api.sandbox.ebay.com/shopping',
headers: {

@@ -125,2 +125,69 @@ 'Content-Type': 'text/xml',

describe('Finding: findItemsByKeywords', function() {
beforeEach('build request', function () {
xmlRequest({
serviceName: 'Finding',
opType: 'findItemsByKeywords',
sandbox: true,
appId: 'ABCDEF',
raw: true, // no parsing
params: {
keywords: ['Canon', 'Powershot'],
outputSelector: ['AspectHistogram'],
itemFilter: [
{name: 'FreeShippingOnly', value: 'true'},
{name: 'MaxPrice', value: '150'},
],
domainFilter: [
{name: 'domainName', value: 'Digital_Cameras'}
],
paginationInput: {
entriesPerPage: '5'
}
}
}, function noop() {
});
});
it('initiated request with expected parameters', function() {
expect(request.post).to.have.been.calledOnce;
expect(request.post.lastCall.args[0]).to.deep.equal({
url: 'http://svcs.sandbox.ebay.com/services/search/FindingService/v1',
headers: {
'X-EBAY-SOA-SECURITY-APPNAME': 'ABCDEF',
'X-EBAY-SOA-REQUEST-DATA-FORMAT': 'XML',
'X-EBAY-SOA-RESPONSE-DATA-FORMAT': 'XML',
'X-EBAY-SOA-GLOBAL-ID': 'EBAY-US',
'X-EBAY-SOA-SERVICE-VERSION': '1.13.0',
'X-EBAY-SOA-OPERATION-NAME': 'findItemsByKeywords'
},
body:
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<findItemsByKeywordsRequest xmlns="http://www.ebay.com/marketplace/search/v1/services">\n' +
' <keywords>Canon</keywords>\n' +
' <keywords>Powershot</keywords>\n' +
' <outputSelector>AspectHistogram</outputSelector>\n' +
' <itemFilter>\n' +
' <name>FreeShippingOnly</name>\n' +
' <value>true</value>\n' +
' </itemFilter>\n' +
' <itemFilter>\n' +
' <name>MaxPrice</name>\n' +
' <value>150</value>\n' +
' </itemFilter>\n' +
' <domainFilter>\n' +
' <name>domainName</name>\n' +
' <value>Digital_Cameras</value>\n' +
' </domainFilter>\n' +
' <paginationInput>\n' +
' <entriesPerPage>5</entriesPerPage>\n' +
' </paginationInput>\n' +
'</findItemsByKeywordsRequest>'
});
});
});
describe('nested params', function() {

@@ -136,3 +203,4 @@ beforeEach('build request', function() {

'ItemTransactionID': {
'OrderLineItemID': '12345-67890'
'OrderLineItemID': '12345-67890',
'SomeOtherID': 'ABCDEF'
}

@@ -151,2 +219,3 @@ }]

' <OrderLineItemID>12345-67890</OrderLineItemID>\n' +
' <SomeOtherID>ABCDEF</SomeOtherID>\n' +
' </ItemTransactionID>\n' +

@@ -168,7 +237,54 @@ ' </ItemTransactionIDArray>\n' +

it('converts everything to an array', function() {
it('converts plain value to array', function() {
expect(_deepToArray(5)).to.deep.equal([5]);
});
it('converts object to array', function() {
expect(_deepToArray({
'a': '1',
'b': '2'
})).to.deep.equal(
[
{'a': ['1']},
{'b': ['2']}
]
);
});
it('splits out array elements into objects', function() {
expect(_deepToArray(
{
thing: ['a', 'b', 'c'],
itemFilter: [
{name: 'FreeShippingOnly', value: 'true'},
{name: 'MaxPrice', value: '150'},
]
}
)).to.deep.equal(
[
{thing: ['a']},
{thing: ['b']},
{thing: ['c']},
{
itemFilter: [
{name: ['FreeShippingOnly']},
{value: ['true']},
]
},
{
itemFilter: [
{name: ['MaxPrice']},
{value: ['150']},
]
}
]
);
});
it('converts everything recursively to arrays', function() {
expect(_deepToArray({
'Thing': {
'Has': {
'Weird': 'Structure'
'Weird': 'Structure',
'Strange': 'Data'
}

@@ -180,18 +296,38 @@ },

'More': 'Things',
'Finally': ['Thing1', 'Thing2']
'Finally': ['Thing1', 'Thing2'],
'Already': [{'An': 'Array'}]
}))
.to.deep.equal({
'Thing': [{
'Has': [{
'Weird': ['Structure']
}]
}],
'Things': [
{'foo': ['bar']}
],
'More': ['Things'],
'Finally': ['Thing1', 'Thing2']
});
.to.deep.equal(
[
{
'Thing': [{
'Has': [
{'Weird': ['Structure']},
{'Strange': ['Data']}
]
}]
},
{
'Things': [
{'foo': ['bar']}
]
},
{
'More': ['Things']
},
{
'Finally': ['Thing1']
},
{
'Finally': ['Thing2']
},
{
'Already': [
{'An': ['Array']}
]
}
]
);
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc