-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
180 lines (156 loc) · 5.54 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
const Ebay = require('ebay');
const forceArray = arr => [].concat(arr !== undefined ? arr : []);
let ebay = null;
/**
* Initialize ebay-find-api
*
* @param {object} config
* @param {object} config.appId - ebay API application identifier (obtained from eBay dev site)
*/
const init = ({ appId }) => {
ebay = new Ebay({
app_id: appId,
});
};
// list of find operations: http://developer.ebay.com/devzone/finding/CallRef/index.html
const findOperations = [
'findCompletedItems',
'findItemsAdvanced',
'findItemsByCategory',
'findItemsByKeywords',
'findItemsByProduct',
'findItemsIneBayStores',
'getHistograms',
'getSearchKeywordsRecommendation',
'getVersion',
];
const validOperation = op => findOperations.includes(op);
const productIdTypes = [
'ReferenceID',
'ISBN',
'UPC',
'EAN',
];
const validProductIdType = type => productIdTypes.includes(type);
/**
* Simple flatten object of arrays to flat object, stops when hits array.length !== 1
*
* @private
* @param {any} arr
* @returns
*/
const flatten = (arr) => {
for (r in arr) {
if (Array.isArray(arr[r]) && arr[r].length === 1)
arr[r] = flatten(arr[r][0]);
}
return arr;
}
/**
* @typedef pagination
* Detailed information about pagination results in a search
* @param {integer} pageNumber - pageNumber returned in this search
* @param {integer} entriesPerPage - number of entries returned per page
* @param {integer} totalPages - total number of pages available in this search
* @param {integer} totalEntries - total number of entries available in this search
*/
/**
* @typedef productSearchResult
* Contains the results of a product search
*
* @param {string} ack - 'Failure' for operation success
* @param {string} version - Version number of API response - ex: 1.13.0
* @param {string} timestamp - UTC string timestamp of response
* @param {integer} searchResultCount - number of results found (may be different from searchResult.length, via pagination)
* @param {searchResult[]} searchResult - array of the found items/listings
* @param {pagination} pagination - detailed info about paging results
* @param {string} intemSearchUrl - the URL to perform the same search on the eBay site
*/
const findCall = operation => parser => baseParams => other => {
if (!validOperation(operation)) {
throw new Error(`invalid operation ${operation} use one of [${findOperations.join(' ')}]`);
}
return new Promise((resolve, reject) => {
const params = {
...other,
'OPERATION-NAME': operation,
...baseParams,
};
ebay.get('finding', params, (err, data) => {
if (err) {
reject(err);
} else {
const { [`${operation}Response`]: response } = flatten(data);
if (!response) {
// Sometimes, a response will come back 100% empty. Not cool.
reject(new Error('eBay Response Empty'));
return;
}
resolve(response);
}
});
}).then(response => parser(response));
};
const findByProductParser = (response) => {
const {
ack, version, timestamp, searchResult, paginationOutput, itemSearchURL,
} = response;
if (searchResult && searchResult.item) {
searchResult.item = forceArray(searchResult.item);
}
if (ack === 'Failure') {
throw response;
}
return ({
ack,
version,
timestamp,
searchResultCount: parseInt(searchResult['@count'], 10) || 0,
searchResult: searchResult && searchResult.item ? searchResult.item.map(flatten) : [],
paginationOutput,
itemSearchUrl: itemSearchURL,
});
};
const callFindByProduct = ({ type, id }) => {
if (!validProductIdType(type)) {
throw new Error(`unknown type ${type}, use one of [${productIdTypes.join(' ')}]`);
}
return findCall('findItemsByProduct')(findByProductParser)({ 'productId.@type': type, productId: id });
}
const callFindItemsAdvanced = str => {
return findCall('findItemsAdvanced')(findByProductParser)({ descriptionSearch: true, keywords: str });
}
/**
* Search for items based on product identifier
*
* @param {string} type - 'ReferenceID', 'ISBN', 'UPC', 'EAN'
* @param {string} id - product identifier code (such as a upc code)
* @param {object} other - other parameters to supply, see http://developer.ebay.com/devzone/finding/CallRef/findItemsByProduct.html
* @returns {productSearchResult} - product search results
*/
const findItemsByProduct = (type, id, other = {}) => {
if (!id) {
return lookupId => callFindByProduct({ type, id: lookupId });
}
return callFindByProduct({ type, id })(other);
}
/**
* Search for items based on product UPC code
*
* @param {string} upc - product upc code
* @param {object} other - other parameters, see http://developer.ebay.com/devzone/finding/CallRef/findItemsByProduct.html
*/
const findItemsByUpc = (upc, other) => findItemsByProduct('UPC')(upc)(other);
const findItemsByReferenceId = (refId, other) => findItemsByProduct('ReferenceID')(refId)(other);
const findItemsByIsbn = (isbn, other) => findItemsByProduct('ISBN')(isbn)(other);
const findItemsByEan = (ean, other) => findItemsByProduct('EAN')(ean)(other);
const findItemsByKeywords = (keywords, other) => callFindItemsAdvanced(keywords)(other);
module.exports = {
init,
findItemsByKeywords,
findItemsByProduct,
findItemsByUpc,
findItemsByReferenceId,
findItemsByIsbn,
findItemsByEan,
};