@constructor-io/constructorio-node 3.10.7 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +3 -2
- package/src/constructorio.js +3 -0
- package/src/modules/catalog.js +316 -253
- package/src/modules/quizzes.js +240 -0
- package/src/utils/helpers.js +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,8 @@ A Node.js client for [Constructor.io](http://constructor.io/). [Constructor.io](
|
|
|
11
11
|
## Documentation
|
|
12
12
|
Full API documentation is available on [Github Pages](https://constructor-io.github.io/constructorio-node)
|
|
13
13
|
|
|
14
|
+
Updating from v3 to v4? Be sure to read the [upgrade guide](https://github.com/Constructor-io/constructorio-node/wiki/Migration-Guide---V3-to-V4) for an explanation of changes made to the Catalog module
|
|
15
|
+
|
|
14
16
|
## 1. Review the Requirements
|
|
15
17
|
|
|
16
18
|
Requesting results from your Node.js back-end can be useful in order to control result rendering logic on your server, or augment/hydrate results with data from another system. However, a back-end integration has additional requirements compared to a front-end integration. Please review the [Additional Information For Backend Integrations](https://github.com/Constructor-io/constructorio-node/wiki/Additional-Information-For-Backend-Integrations) article within the wiki for more detail.
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructor-io/constructorio-node",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Constructor.io Node.js client",
|
|
5
5
|
"main": "src/constructorio.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"version": "chmod +x ./scripts/verify-node-version.sh && ./scripts/verify-node-version.sh && npm run docs && git add ./docs/*",
|
|
8
8
|
"check-lisc": "license-checker --production --onlyAllow 'Apache-2.0;BSD-3-Clause;MIT'",
|
|
9
9
|
"lint": "eslint 'src/**/*.js' 'spec/**/*.js'",
|
|
10
|
+
"test:parallel": "mkdir -p test && cp -rf src/* test && mocha --parallel ./spec/*",
|
|
10
11
|
"test": "mkdir -p test && cp -rf src/* test && mocha ./spec/*",
|
|
11
12
|
"precoverage": "rm -rf ./coverage && rm -rf ./.nyc_output",
|
|
12
|
-
"coverage": "nyc --all --reporter=html npm run test",
|
|
13
|
+
"coverage": "nyc --all --reporter=html npm run test:parallel",
|
|
13
14
|
"postcoverage": "open coverage/index.html && rm -rf test",
|
|
14
15
|
"docs": "jsdoc --configure ./.jsdoc.json ./README.md --recurse ./src --destination ./docs",
|
|
15
16
|
"prepare": "husky install"
|
package/src/constructorio.js
CHANGED
|
@@ -8,6 +8,7 @@ const Recommendations = require('./modules/recommendations');
|
|
|
8
8
|
const Tracker = require('./modules/tracker');
|
|
9
9
|
const Catalog = require('./modules/catalog');
|
|
10
10
|
const Tasks = require('./modules/tasks');
|
|
11
|
+
const Quizzes = require('./modules/quizzes');
|
|
11
12
|
const { version: packageVersion } = require('../package.json');
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -30,6 +31,7 @@ class ConstructorIO {
|
|
|
30
31
|
* @property {object} tracker - Interface to {@link module:tracker}
|
|
31
32
|
* @property {object} catalog - Interface to {@link module:catalog}
|
|
32
33
|
* @property {object} tasks - Interface to {@link module:tasks}
|
|
34
|
+
* @property {object} quizzes - Interface to {@link module:quizzes}
|
|
33
35
|
* @returns {class}
|
|
34
36
|
*/
|
|
35
37
|
constructor(options = {}) {
|
|
@@ -65,6 +67,7 @@ class ConstructorIO {
|
|
|
65
67
|
this.tracker = new Tracker(this.options);
|
|
66
68
|
this.catalog = new Catalog(this.options);
|
|
67
69
|
this.tasks = new Tasks(this.options);
|
|
70
|
+
this.quizzes = new Quizzes(this.options);
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
|
package/src/modules/catalog.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
1
2
|
/* eslint-disable object-curly-newline, no-underscore-dangle, max-len */
|
|
2
3
|
const qs = require('qs');
|
|
3
4
|
const nodeFetch = require('node-fetch').default;
|
|
@@ -55,7 +56,7 @@ async function createQueryParamsAndFormData(parameters) {
|
|
|
55
56
|
const formData = new FormData();
|
|
56
57
|
|
|
57
58
|
if (parameters) {
|
|
58
|
-
const { section,
|
|
59
|
+
const { section, notificationEmail, force } = parameters;
|
|
59
60
|
let { items, variations, item_groups: itemGroups } = parameters;
|
|
60
61
|
|
|
61
62
|
try {
|
|
@@ -130,54 +131,62 @@ class Catalog {
|
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
/**
|
|
133
|
-
*
|
|
134
|
+
* Adds multiple items to your index whilst replacing existing ones (limit of 1,000)
|
|
134
135
|
*
|
|
135
|
-
* @function
|
|
136
|
+
* @function createOrReplaceItems
|
|
136
137
|
* @param {object} parameters - Additional parameters for item details
|
|
137
|
-
* @param {
|
|
138
|
-
* @param {
|
|
139
|
-
* @param {
|
|
140
|
-
* @param {string
|
|
141
|
-
* @param {string} [parameters.url] - A URL to directly send the user after selecting the item
|
|
142
|
-
* @param {string} [parameters.image_url] - A URL that points to an image you'd like displayed next to some item (only applicable when URL is supplied)
|
|
143
|
-
* @param {string} [parameters.description] - A description for some item (only applicable when URL is supplied)
|
|
144
|
-
* @param {string} [parameters.id] - An arbitrary ID you would like associated with this item. You can use this field to store your own IDs of the items to more easily access them in other API calls
|
|
145
|
-
* @param {object} [parameters.facets] - Key/value pairs that can be associated with an item and used to filter them during a search. You can associate multiple values with the same key, by making values a list. Facets can be used as filters in search, autosuggest, and browse requests
|
|
146
|
-
* @param {object} [parameters.metadata] - You can associate schema-less data with items by passing in an object of keys and values. To configure search and display of this data reach out to support@constructor.io
|
|
147
|
-
* @param {string[]} [parameters.group_ids] - You can associate each item with one or more groups (i.e. categories). To set up a group hierarchy please contact support@constructor.io. group_ids can be used as filters in search, autosuggest, and browse requests
|
|
148
|
-
* @param {object[]} [parameters.variations] - List of this item's variations
|
|
138
|
+
* @param {object[]} parameters.items - A list of items with the same attributes as defined in the Item schema resource (https://docs.constructor.io/rest_api/items/items/#item-schema)
|
|
139
|
+
* @param {boolean} [parameters.force=false] - Process the request even if it will invalidate a large number of existing items
|
|
140
|
+
* @param {string} [parameters.notificationEmail] - An email address where you'd like to receive an email notification in case the task fails
|
|
141
|
+
* @param {string} [parameters.section="Products"] - This indicates which section to operate on within the index
|
|
149
142
|
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
150
143
|
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
151
144
|
* @returns {Promise}
|
|
152
|
-
* @see https://docs.constructor.io/rest_api/items/
|
|
145
|
+
* @see https://docs.constructor.io/rest_api/items/items#create-or-replace-items
|
|
153
146
|
* @example
|
|
154
|
-
* constructorio.catalog.
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* on_sale: true,
|
|
169
|
-
* },
|
|
170
|
-
* group_ids: ['cat_49203', 'subcat_12891'],
|
|
147
|
+
* constructorio.catalog.createOrReplaceItems({
|
|
148
|
+
* items: [
|
|
149
|
+
* {
|
|
150
|
+
* name: 'midnight black pullover hoodie',
|
|
151
|
+
* id: 'blk_pllvr_hd_001',
|
|
152
|
+
* data: {
|
|
153
|
+
* keywords: ['midnight black', 'black', 'hoodie', 'tops', 'outerwear'],
|
|
154
|
+
* url: '/products/blk_pllvr_hd_001'
|
|
155
|
+
* image_url: '/products/images/blk_pllvr_hd_001'
|
|
156
|
+
* description: 'a modified short description about the black pullover hoodie',
|
|
157
|
+
* }
|
|
158
|
+
* },
|
|
159
|
+
* ...
|
|
160
|
+
* ],
|
|
171
161
|
* });
|
|
172
162
|
*/
|
|
173
|
-
|
|
163
|
+
createOrReplaceItems(parameters = {}, networkParameters = {}) {
|
|
174
164
|
let requestUrl;
|
|
175
165
|
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
176
166
|
const controller = new AbortController();
|
|
177
167
|
const { signal } = controller;
|
|
168
|
+
const { items, section, force, notificationEmail } = parameters;
|
|
169
|
+
const queryParams = {};
|
|
170
|
+
|
|
171
|
+
// Validate items is provided
|
|
172
|
+
if (!items || !Array.isArray(items)) {
|
|
173
|
+
return Promise.reject(new Error('items is a required parameter of type array'));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (section) {
|
|
177
|
+
queryParams.section = section;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (force) {
|
|
181
|
+
queryParams.force = force;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (notificationEmail) {
|
|
185
|
+
queryParams.notification_email = notificationEmail;
|
|
186
|
+
}
|
|
178
187
|
|
|
179
188
|
try {
|
|
180
|
-
requestUrl = createCatalogUrl('
|
|
189
|
+
requestUrl = createCatalogUrl('items', this.options, queryParams, 'v2');
|
|
181
190
|
} catch (e) {
|
|
182
191
|
return Promise.reject(e);
|
|
183
192
|
}
|
|
@@ -186,8 +195,8 @@ class Catalog {
|
|
|
186
195
|
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
|
|
187
196
|
|
|
188
197
|
return fetch(requestUrl, {
|
|
189
|
-
method: '
|
|
190
|
-
body: JSON.stringify(
|
|
198
|
+
method: 'PUT',
|
|
199
|
+
body: JSON.stringify({ items }),
|
|
191
200
|
headers: {
|
|
192
201
|
'Content-Type': 'application/json',
|
|
193
202
|
...helpers.createAuthHeader(this.options),
|
|
@@ -203,54 +212,63 @@ class Catalog {
|
|
|
203
212
|
}
|
|
204
213
|
|
|
205
214
|
/**
|
|
206
|
-
*
|
|
215
|
+
* Update multiple items to index (limit of 1,000)
|
|
207
216
|
*
|
|
208
|
-
* @function
|
|
217
|
+
* @function updateItems
|
|
209
218
|
* @param {object} parameters - Additional parameters for item details
|
|
210
|
-
* @param {
|
|
211
|
-
* @param {
|
|
212
|
-
* @param {
|
|
213
|
-
* @param {string
|
|
214
|
-
* @param {string} [parameters.url] - A URL to directly send the user after selecting the item
|
|
215
|
-
* @param {string} [parameters.image_url] - A URL that points to an image you'd like displayed next to some item (only applicable when URL is supplied)
|
|
216
|
-
* @param {string} [parameters.description] - A description for some item (only applicable when URL is supplied)
|
|
217
|
-
* @param {string} [parameters.id] - An arbitrary ID you would like associated with this item. You can use this field to store your own IDs of the items to more easily access them in other API calls
|
|
218
|
-
* @param {object} [parameters.facets] - Key/value pairs that can be associated with an item and used to filter them during a search. You can associate multiple values with the same key, by making values a list. Facets can be used as filters in search, autosuggest, and browse requests
|
|
219
|
-
* @param {object} [parameters.metadata] - You can associate schema-less data with items by passing in an object of keys and values. To configure search and display of this data reach out to support@constructor.io
|
|
220
|
-
* @param {string[]} [parameters.group_ids] - You can associate each item with one or more groups (i.e. categories). To set up a group hierarchy please contact support@constructor.io. group_ids can be used as filters in search, autosuggest, and browse requests
|
|
221
|
-
* @param {object[]} [parameters.variations] - List of this item's variations
|
|
219
|
+
* @param {object[]} parameters.items - A list of items with the same attributes as defined in the Item schema resource (https://docs.constructor.io/rest_api/items/items/#item-schema)
|
|
220
|
+
* @param {boolean} [parameters.force=false] - Process the request even if it will invalidate a large number of existing items
|
|
221
|
+
* @param {string} [parameters.notificationEmail] - An email address where you'd like to receive an email notification in case the task fails
|
|
222
|
+
* @param {string} [parameters.section="Products"] - This indicates which section to operate on within the index
|
|
222
223
|
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
223
224
|
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
224
225
|
* @returns {Promise}
|
|
225
|
-
* @see https://docs.constructor.io/rest_api/items/
|
|
226
|
+
* @see https://docs.constructor.io/rest_api/items/items#update-items
|
|
226
227
|
* @example
|
|
227
|
-
* constructorio.catalog.
|
|
228
|
-
*
|
|
228
|
+
* constructorio.catalog.updateItems({
|
|
229
|
+
* items: [
|
|
230
|
+
* {
|
|
231
|
+
* name: 'midnight black pullover hoodie',
|
|
232
|
+
* id: 'blk_pllvr_hd_001',
|
|
233
|
+
* data: {
|
|
234
|
+
* keywords: ['midnight black', 'black', 'hoodie', 'tops', 'outerwear'],
|
|
235
|
+
* url: '/products/blk_pllvr_hd_001'
|
|
236
|
+
* image_url: '/products/images/blk_pllvr_hd_001'
|
|
237
|
+
* description: 'a modified short description about the black pullover hoodie',
|
|
238
|
+
* }
|
|
239
|
+
* },
|
|
240
|
+
* . . .
|
|
241
|
+
* ],
|
|
229
242
|
* section: 'Products',
|
|
230
|
-
* keywords: ['black', 'hoodie', 'tops', 'outerwear'],
|
|
231
|
-
* url: '/products/blk_pllvr_hd_001'
|
|
232
|
-
* image_url: '/products/images/blk_pllvr_hd_001'
|
|
233
|
-
* description: 'a short description about the black pullover hoodie',
|
|
234
|
-
* id: 'blk_pllvr_hd_001',
|
|
235
|
-
* facets: {
|
|
236
|
-
* size: 'medium',
|
|
237
|
-
* color: 'black',
|
|
238
|
-
* },
|
|
239
|
-
* metadata: {
|
|
240
|
-
* swatch_image_url: '/products/swatch_images/blk_pllvr_hd_001',
|
|
241
|
-
* on_sale: true,
|
|
242
|
-
* },
|
|
243
|
-
* group_ids: ['cat_49203', 'subcat_12891'],
|
|
244
243
|
* });
|
|
245
244
|
*/
|
|
246
|
-
|
|
245
|
+
updateItems(parameters = {}, networkParameters = {}) {
|
|
247
246
|
let requestUrl;
|
|
248
247
|
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
249
248
|
const controller = new AbortController();
|
|
250
249
|
const { signal } = controller;
|
|
250
|
+
const { items, section, force, notificationEmail } = parameters;
|
|
251
|
+
const queryParams = {};
|
|
252
|
+
|
|
253
|
+
// Validate items is provided
|
|
254
|
+
if (!items || !Array.isArray(items)) {
|
|
255
|
+
return Promise.reject(new Error('items is a required parameter of type array'));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (notificationEmail) {
|
|
259
|
+
queryParams.notification_email = notificationEmail;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (section) {
|
|
263
|
+
queryParams.section = section;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (force) {
|
|
267
|
+
queryParams.force = force;
|
|
268
|
+
}
|
|
251
269
|
|
|
252
270
|
try {
|
|
253
|
-
requestUrl =
|
|
271
|
+
requestUrl = createCatalogUrl('items', this.options, queryParams, 'v2');
|
|
254
272
|
} catch (e) {
|
|
255
273
|
return Promise.reject(e);
|
|
256
274
|
}
|
|
@@ -259,8 +277,8 @@ class Catalog {
|
|
|
259
277
|
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
|
|
260
278
|
|
|
261
279
|
return fetch(requestUrl, {
|
|
262
|
-
method: '
|
|
263
|
-
body: JSON.stringify(
|
|
280
|
+
method: 'PATCH',
|
|
281
|
+
body: JSON.stringify({ items }),
|
|
264
282
|
headers: {
|
|
265
283
|
'Content-Type': 'application/json',
|
|
266
284
|
...helpers.createAuthHeader(this.options),
|
|
@@ -276,31 +294,53 @@ class Catalog {
|
|
|
276
294
|
}
|
|
277
295
|
|
|
278
296
|
/**
|
|
279
|
-
* Remove
|
|
297
|
+
* Remove multiple items from your index (limit of 1,000)
|
|
280
298
|
*
|
|
281
|
-
* @function
|
|
299
|
+
* @function deleteItems
|
|
282
300
|
* @param {object} parameters - Additional parameters for item details
|
|
283
|
-
* @param {
|
|
284
|
-
* @param {string} parameters.section
|
|
285
|
-
* @param {string} parameters.
|
|
301
|
+
* @param {object[]} parameters.items - A list of items with the same attributes as defined in the Item schema resource (https://docs.constructor.io/rest_api/items/items/#item-schema)
|
|
302
|
+
* @param {string} [parameters.section="Products"] - This indicates which section to operate on within the index
|
|
303
|
+
* @param {string} [parameters.notificationEmail] - An email address where you'd like to receive an email notification in case the task fails
|
|
286
304
|
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
287
305
|
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
288
306
|
* @returns {Promise}
|
|
289
|
-
* @see https://docs.constructor.io/rest_api/items/
|
|
307
|
+
* @see https://docs.constructor.io/rest_api/items/items#delete-items
|
|
290
308
|
* @example
|
|
291
|
-
* constructorio.catalog.
|
|
292
|
-
*
|
|
309
|
+
* constructorio.catalog.deleteItems({
|
|
310
|
+
* items: [
|
|
311
|
+
* { id: 'blk_pllvr_hd_001' },
|
|
312
|
+
* { id: 'red_pllvr_hd_02' },
|
|
313
|
+
* ],
|
|
293
314
|
* section: 'Products',
|
|
294
315
|
* });
|
|
295
316
|
*/
|
|
296
|
-
|
|
317
|
+
deleteItems(parameters = {}, networkParameters = {}) {
|
|
297
318
|
let requestUrl;
|
|
298
319
|
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
299
320
|
const controller = new AbortController();
|
|
300
321
|
const { signal } = controller;
|
|
322
|
+
const { items, section, force, notificationEmail } = parameters;
|
|
323
|
+
const queryParams = {};
|
|
324
|
+
|
|
325
|
+
// Validate items is provided
|
|
326
|
+
if (!items || !Array.isArray(items)) {
|
|
327
|
+
return Promise.reject(new Error('items is a required parameter of type array'));
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (section) {
|
|
331
|
+
queryParams.section = section;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (force) {
|
|
335
|
+
queryParams.force = force;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (notificationEmail) {
|
|
339
|
+
queryParams.notification_email = notificationEmail;
|
|
340
|
+
}
|
|
301
341
|
|
|
302
342
|
try {
|
|
303
|
-
requestUrl = createCatalogUrl('
|
|
343
|
+
requestUrl = createCatalogUrl('items', this.options, queryParams, 'v2');
|
|
304
344
|
} catch (e) {
|
|
305
345
|
return Promise.reject(e);
|
|
306
346
|
}
|
|
@@ -310,7 +350,7 @@ class Catalog {
|
|
|
310
350
|
|
|
311
351
|
return fetch(requestUrl, {
|
|
312
352
|
method: 'DELETE',
|
|
313
|
-
body: JSON.stringify(
|
|
353
|
+
body: JSON.stringify({ items }),
|
|
314
354
|
headers: {
|
|
315
355
|
'Content-Type': 'application/json',
|
|
316
356
|
...helpers.createAuthHeader(this.options),
|
|
@@ -326,55 +366,58 @@ class Catalog {
|
|
|
326
366
|
}
|
|
327
367
|
|
|
328
368
|
/**
|
|
329
|
-
*
|
|
369
|
+
* Retrieves item(s) from index for the given section or specific item ID
|
|
330
370
|
*
|
|
331
|
-
* @function
|
|
371
|
+
* @function retrieveItems
|
|
332
372
|
* @param {object} parameters - Additional parameters for item details
|
|
333
|
-
* @param {string} parameters.
|
|
334
|
-
* @param {string} parameters.
|
|
335
|
-
* @param {
|
|
336
|
-
* @param {number} [parameters.
|
|
337
|
-
* @param {string[]} [parameters.keywords] - An array of keywords for this item. Keywords are useful if you want a product name to appear when a user enters a searchterm that isn't in the product name itself
|
|
338
|
-
* @param {string} [parameters.url] - A URL to directly send the user after selecting the item
|
|
339
|
-
* @param {string} [parameters.image_url] - A URL that points to an image you'd like displayed next to some item (only applicable when URL is supplied)
|
|
340
|
-
* @param {string} [parameters.description] - A description for some item (only applicable when URL is supplied)
|
|
341
|
-
* @param {string} [parameters.id] - An arbitrary ID you would like associated with this item. You can use this field to store your own IDs of the items to more easily access them in other API calls
|
|
342
|
-
* @param {object} [parameters.facets] - Key/value pairs that can be associated with an item and used to filter them during a search. You can associate multiple values with the same key, by making values a list. Facets can be used as filters in search, autosuggest, and browse requests
|
|
343
|
-
* @param {object} [parameters.metadata] - You can associate schema-less data with items by passing in an object of keys and values. To configure search and display of this data reach out to support@constructor.io
|
|
344
|
-
* @param {string[]} [parameters.group_ids] - You can associate each item with one or more groups (i.e. categories). To set up a group hierarchy please contact support@constructor.io. group_ids can be used as filters in search, autosuggest, and browse requests
|
|
345
|
-
* @param {object[]} [parameters.variations] - List of this item's variations
|
|
373
|
+
* @param {string[]} [parameters.ids] - Id(s) of items to return (1,000 maximum)
|
|
374
|
+
* @param {string} [parameters.section] - This indicates which section to operate on within the index
|
|
375
|
+
* @param {number} [parameters.numResultsPerPage=100] - The number of items to return
|
|
376
|
+
* @param {number} [parameters.page=1] - The page of results to return
|
|
346
377
|
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
347
378
|
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
348
379
|
* @returns {Promise}
|
|
349
|
-
* @see https://docs.constructor.io/rest_api/items/
|
|
380
|
+
* @see https://docs.constructor.io/rest_api/items/items#retrieve-items
|
|
350
381
|
* @example
|
|
351
|
-
* constructorio.catalog.
|
|
352
|
-
* item_name: 'midnight black pullover hoodie',
|
|
382
|
+
* constructorio.catalog.retrieveItems({
|
|
353
383
|
* section: 'Products',
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
* metadata: {
|
|
364
|
-
* swatch_image_url: '/products/swatch_images/blk_pllvr_hd_001',
|
|
365
|
-
* on_sale: true,
|
|
366
|
-
* },
|
|
367
|
-
* group_ids: ['cat_49203', 'subcat_12891'],
|
|
384
|
+
* numResultsPerPage: 50,
|
|
385
|
+
* page: 2,
|
|
386
|
+
* });
|
|
387
|
+
* @example
|
|
388
|
+
* constructorio.catalog.retrieveItems({
|
|
389
|
+
* ids: ['blk_pllvr_hd_001', 'blk_pllvr_hd_002']
|
|
390
|
+
* section: 'Products',
|
|
391
|
+
* numResultsPerPage: 50,
|
|
392
|
+
* page: 2,
|
|
368
393
|
* });
|
|
369
394
|
*/
|
|
370
|
-
|
|
395
|
+
retrieveItems(parameters = {}, networkParameters = {}) {
|
|
371
396
|
let requestUrl;
|
|
372
397
|
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
373
398
|
const controller = new AbortController();
|
|
374
399
|
const { signal } = controller;
|
|
400
|
+
const { ids, section, numResultsPerPage, page } = parameters;
|
|
401
|
+
const queryParams = {};
|
|
402
|
+
|
|
403
|
+
if (ids) {
|
|
404
|
+
queryParams.id = ids;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (section) {
|
|
408
|
+
queryParams.section = section;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (numResultsPerPage) {
|
|
412
|
+
queryParams.num_results_per_page = numResultsPerPage;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (page) {
|
|
416
|
+
queryParams.page = page;
|
|
417
|
+
}
|
|
375
418
|
|
|
376
419
|
try {
|
|
377
|
-
requestUrl = createCatalogUrl('
|
|
420
|
+
requestUrl = createCatalogUrl('items', this.options, queryParams, 'v2');
|
|
378
421
|
} catch (e) {
|
|
379
422
|
return Promise.reject(e);
|
|
380
423
|
}
|
|
@@ -383,8 +426,7 @@ class Catalog {
|
|
|
383
426
|
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
|
|
384
427
|
|
|
385
428
|
return fetch(requestUrl, {
|
|
386
|
-
method: '
|
|
387
|
-
body: JSON.stringify(parameters),
|
|
429
|
+
method: 'GET',
|
|
388
430
|
headers: {
|
|
389
431
|
'Content-Type': 'application/json',
|
|
390
432
|
...helpers.createAuthHeader(this.options),
|
|
@@ -392,49 +434,73 @@ class Catalog {
|
|
|
392
434
|
signal,
|
|
393
435
|
}).then((response) => {
|
|
394
436
|
if (response.ok) {
|
|
395
|
-
|
|
437
|
+
|
|
438
|
+
return response.json();
|
|
396
439
|
}
|
|
397
440
|
|
|
398
441
|
return helpers.throwHttpErrorFromResponse(new Error(), response);
|
|
399
|
-
});
|
|
442
|
+
}).then((json) => json);
|
|
400
443
|
}
|
|
401
444
|
|
|
402
445
|
/**
|
|
403
|
-
*
|
|
446
|
+
* Adds multiple variations to your index whilst replacing existing ones (limit of 1,000)
|
|
404
447
|
*
|
|
405
|
-
* @function
|
|
406
|
-
* @param {object} parameters - Additional parameters for
|
|
407
|
-
* @param {object[]} parameters.
|
|
408
|
-
* @param {
|
|
448
|
+
* @function createOrReplaceVariations
|
|
449
|
+
* @param {object} parameters - Additional parameters for variation details
|
|
450
|
+
* @param {object[]} parameters.variations - A list of variations with the same attributes as defined in the Variation schema resource (https://docs.constructor.io/rest_api/items/variations/#variation-schema)
|
|
451
|
+
* @param {boolean} [parameters.force=false] - Process the request even if it will invalidate a large number of existing variations
|
|
452
|
+
* @param {string} [parameters.notificationEmail] - An email address where you'd like to receive an email notification in case the task fails
|
|
453
|
+
* @param {string} [parameters.section="Products"] - This indicates which section to operate on within the index
|
|
409
454
|
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
410
455
|
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
411
456
|
* @returns {Promise}
|
|
412
|
-
* @see https://docs.constructor.io/rest_api/items/
|
|
457
|
+
* @see https://docs.constructor.io/rest_api/items/variations/#create-or-replace-variations
|
|
413
458
|
* @example
|
|
414
|
-
* constructorio.catalog.
|
|
415
|
-
*
|
|
459
|
+
* constructorio.catalog.createOrReplaceVariations({
|
|
460
|
+
* variations: [
|
|
416
461
|
* {
|
|
417
|
-
*
|
|
418
|
-
* section: 'Products',
|
|
419
|
-
* keywords: ['midnight black', 'black', 'hoodie', 'tops', 'outerwear'],
|
|
420
|
-
* url: '/products/blk_pllvr_hd_001'
|
|
421
|
-
* image_url: '/products/images/blk_pllvr_hd_001'
|
|
422
|
-
* description: 'a modified short description about the black pullover hoodie',
|
|
462
|
+
* name: 'midnight black pullover hoodie',
|
|
423
463
|
* id: 'blk_pllvr_hd_001',
|
|
464
|
+
* item_id: "nike-shoes-brown",
|
|
465
|
+
* data: {
|
|
466
|
+
* keywords: ['midnight black', 'black', 'hoodie', 'tops', 'outerwear'],
|
|
467
|
+
* url: '/products/blk_pllvr_hd_001'
|
|
468
|
+
* image_url: '/products/images/blk_pllvr_hd_001'
|
|
469
|
+
* description: 'a modified short description about the black pullover hoodie',
|
|
470
|
+
* }
|
|
424
471
|
* },
|
|
425
|
-
*
|
|
472
|
+
* ...
|
|
426
473
|
* ],
|
|
427
474
|
* section: 'Products',
|
|
428
475
|
* });
|
|
429
476
|
*/
|
|
430
|
-
|
|
477
|
+
createOrReplaceVariations(parameters = {}, networkParameters = {}) {
|
|
431
478
|
let requestUrl;
|
|
432
479
|
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
433
480
|
const controller = new AbortController();
|
|
434
481
|
const { signal } = controller;
|
|
482
|
+
const { section, force, notificationEmail, variations } = parameters;
|
|
483
|
+
const queryParams = {};
|
|
484
|
+
|
|
485
|
+
// Validate variations are provided
|
|
486
|
+
if (!variations || !Array.isArray(variations)) {
|
|
487
|
+
return Promise.reject(new Error('variations is a required parameter of type array'));
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (notificationEmail) {
|
|
491
|
+
queryParams.notification_email = notificationEmail;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (section) {
|
|
495
|
+
queryParams.section = section;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (force) {
|
|
499
|
+
queryParams.force = force;
|
|
500
|
+
}
|
|
435
501
|
|
|
436
502
|
try {
|
|
437
|
-
requestUrl = createCatalogUrl('
|
|
503
|
+
requestUrl = createCatalogUrl('variations', this.options, queryParams, 'v2');
|
|
438
504
|
} catch (e) {
|
|
439
505
|
return Promise.reject(e);
|
|
440
506
|
}
|
|
@@ -443,8 +509,8 @@ class Catalog {
|
|
|
443
509
|
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
|
|
444
510
|
|
|
445
511
|
return fetch(requestUrl, {
|
|
446
|
-
method: '
|
|
447
|
-
body: JSON.stringify(
|
|
512
|
+
method: 'PUT',
|
|
513
|
+
body: JSON.stringify({ variations }),
|
|
448
514
|
headers: {
|
|
449
515
|
'Content-Type': 'application/json',
|
|
450
516
|
...helpers.createAuthHeader(this.options),
|
|
@@ -460,41 +526,64 @@ class Catalog {
|
|
|
460
526
|
}
|
|
461
527
|
|
|
462
528
|
/**
|
|
463
|
-
*
|
|
529
|
+
* Update multiple variations to index (limit of 1,000)
|
|
464
530
|
*
|
|
465
|
-
* @function
|
|
466
|
-
* @param {object} parameters - Additional parameters for
|
|
467
|
-
* @param {object[]} parameters.
|
|
468
|
-
* @param {
|
|
531
|
+
* @function updateVariations
|
|
532
|
+
* @param {object} parameters - Additional parameters for variation details
|
|
533
|
+
* @param {object[]} parameters.variations - A list of variations with the same attributes as defined in the Variation schema resource (https://docs.constructor.io/rest_api/items/variations/#variation-schema)
|
|
534
|
+
* @param {boolean} [parameters.force=false] - Process the request even if it will invalidate a large number of existing variations
|
|
535
|
+
* @param {string} [parameters.notificationEmail] - An email address where you'd like to receive an email notification in case the task fails
|
|
536
|
+
* @param {string} [parameters.section="Products"] - This indicates which section to operate on within the index
|
|
469
537
|
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
470
538
|
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
471
539
|
* @returns {Promise}
|
|
472
|
-
* @see https://docs.constructor.io/rest_api/items/
|
|
540
|
+
* @see https://docs.constructor.io/rest_api/items/variations/#update-variations
|
|
473
541
|
* @example
|
|
474
|
-
* constructorio.catalog.
|
|
475
|
-
*
|
|
542
|
+
* constructorio.catalog.updateVariations({
|
|
543
|
+
* variations: [
|
|
476
544
|
* {
|
|
477
|
-
*
|
|
478
|
-
* section: 'Products',
|
|
479
|
-
* keywords: ['midnight black', 'black', 'hoodie', 'tops', 'outerwear'],
|
|
480
|
-
* url: '/products/blk_pllvr_hd_001'
|
|
481
|
-
* image_url: '/products/images/blk_pllvr_hd_001'
|
|
482
|
-
* description: 'a modified short description about the black pullover hoodie',
|
|
545
|
+
* name: 'midnight black pullover hoodie',
|
|
483
546
|
* id: 'blk_pllvr_hd_001',
|
|
547
|
+
* item_id: "nike-shoes-brown",
|
|
548
|
+
* data: {
|
|
549
|
+
* keywords: ['midnight black', 'black', 'hoodie', 'tops', 'outerwear'],
|
|
550
|
+
* url: '/products/blk_pllvr_hd_001'
|
|
551
|
+
* image_url: '/products/images/blk_pllvr_hd_001'
|
|
552
|
+
* description: 'a modified short description about the black pullover hoodie',
|
|
553
|
+
* }
|
|
484
554
|
* },
|
|
485
|
-
*
|
|
555
|
+
* ...
|
|
486
556
|
* ],
|
|
487
557
|
* section: 'Products',
|
|
488
558
|
* });
|
|
489
559
|
*/
|
|
490
|
-
|
|
560
|
+
updateVariations(parameters = {}, networkParameters = {}) {
|
|
491
561
|
let requestUrl;
|
|
492
562
|
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
493
563
|
const controller = new AbortController();
|
|
494
564
|
const { signal } = controller;
|
|
565
|
+
const { section, force, notificationEmail, variations } = parameters;
|
|
566
|
+
const queryParams = {};
|
|
567
|
+
|
|
568
|
+
// Validate variations are provided
|
|
569
|
+
if (!variations || !Array.isArray(variations)) {
|
|
570
|
+
return Promise.reject(new Error('variations is a required parameter of type array'));
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
if (section) {
|
|
574
|
+
queryParams.section = section;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (force) {
|
|
578
|
+
queryParams.force = force;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (notificationEmail) {
|
|
582
|
+
queryParams.notification_email = notificationEmail;
|
|
583
|
+
}
|
|
495
584
|
|
|
496
585
|
try {
|
|
497
|
-
requestUrl =
|
|
586
|
+
requestUrl = createCatalogUrl('variations', this.options, queryParams, 'v2');
|
|
498
587
|
} catch (e) {
|
|
499
588
|
return Promise.reject(e);
|
|
500
589
|
}
|
|
@@ -503,8 +592,8 @@ class Catalog {
|
|
|
503
592
|
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
|
|
504
593
|
|
|
505
594
|
return fetch(requestUrl, {
|
|
506
|
-
method: '
|
|
507
|
-
body: JSON.stringify(
|
|
595
|
+
method: 'PATCH',
|
|
596
|
+
body: JSON.stringify({ variations }),
|
|
508
597
|
headers: {
|
|
509
598
|
'Content-Type': 'application/json',
|
|
510
599
|
...helpers.createAuthHeader(this.options),
|
|
@@ -520,94 +609,54 @@ class Catalog {
|
|
|
520
609
|
}
|
|
521
610
|
|
|
522
611
|
/**
|
|
523
|
-
* Remove multiple
|
|
612
|
+
* Remove multiple variations from your index (limit of 1,000)
|
|
524
613
|
*
|
|
525
|
-
* @function
|
|
526
|
-
* @param {object} parameters - Additional parameters for
|
|
527
|
-
* @param {object[]} parameters.
|
|
528
|
-
* @param {
|
|
614
|
+
* @function deleteVariations
|
|
615
|
+
* @param {object} parameters - Additional parameters for variation details
|
|
616
|
+
* @param {object[]} parameters.variations - A list of variations with the same attributes as defined in the Variation schema resource (https://docs.constructor.io/rest_api/items/variations/#variation-schema)
|
|
617
|
+
* @param {boolean} [parameters.force=false] - Process the request even if it will invalidate a large number of existing variations
|
|
618
|
+
* @param {string} [parameters.notificationEmail] - An email address where you'd like to receive an email notification in case the task fails
|
|
619
|
+
* @param {string} [parameters.section="Products"] - This indicates which section to operate on within the index
|
|
529
620
|
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
530
621
|
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
531
622
|
* @returns {Promise}
|
|
532
|
-
* @see https://docs.constructor.io/rest_api/items/
|
|
623
|
+
* @see https://docs.constructor.io/rest_api/items/variations/#delete-variations
|
|
533
624
|
* @example
|
|
534
|
-
* constructorio.catalog.
|
|
535
|
-
*
|
|
625
|
+
* constructorio.catalog.deleteVariations({
|
|
626
|
+
* variations: [
|
|
536
627
|
* { id: 'blk_pllvr_hd_001' },
|
|
537
628
|
* { id: 'red_pllvr_hd_02' },
|
|
538
629
|
* ],
|
|
539
630
|
* section: 'Products',
|
|
540
631
|
* });
|
|
541
632
|
*/
|
|
542
|
-
|
|
633
|
+
deleteVariations(parameters = {}, networkParameters = {}) {
|
|
543
634
|
let requestUrl;
|
|
544
635
|
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
545
636
|
const controller = new AbortController();
|
|
546
637
|
const { signal } = controller;
|
|
638
|
+
const { section, force, notificationEmail, variations } = parameters;
|
|
639
|
+
const queryParams = {};
|
|
547
640
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
return Promise.reject(e);
|
|
641
|
+
// Validate variations are provided
|
|
642
|
+
if (!variations || !Array.isArray(variations)) {
|
|
643
|
+
return Promise.reject(new Error('variations is a required parameter of type array'));
|
|
552
644
|
}
|
|
553
645
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
return fetch(requestUrl, {
|
|
558
|
-
method: 'DELETE',
|
|
559
|
-
body: JSON.stringify(parameters),
|
|
560
|
-
headers: {
|
|
561
|
-
'Content-Type': 'application/json',
|
|
562
|
-
...helpers.createAuthHeader(this.options),
|
|
563
|
-
},
|
|
564
|
-
signal,
|
|
565
|
-
}).then((response) => {
|
|
566
|
-
if (response.ok) {
|
|
567
|
-
return Promise.resolve();
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
return helpers.throwHttpErrorFromResponse(new Error(), response);
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
/**
|
|
575
|
-
* Retrieves item(s) from index for the given section or specific item ID
|
|
576
|
-
*
|
|
577
|
-
* @function getItem
|
|
578
|
-
* @param {object} parameters - Additional parameters for item details
|
|
579
|
-
* @param {string} parameters.id - The ID of the item you'd like to retrieve
|
|
580
|
-
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
581
|
-
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
582
|
-
* @returns {Promise}
|
|
583
|
-
* @see https://docs.constructor.io/rest_api/items/v1/get_items
|
|
584
|
-
* @example
|
|
585
|
-
* constructorio.catalog.getItem({
|
|
586
|
-
* id: 'blk_pllvr_hd_001',
|
|
587
|
-
* });
|
|
588
|
-
*/
|
|
589
|
-
getItem(parameters = {}, networkParameters = {}) {
|
|
590
|
-
const queryParams = {};
|
|
591
|
-
let requestUrl;
|
|
592
|
-
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
593
|
-
const controller = new AbortController();
|
|
594
|
-
const { signal } = controller;
|
|
646
|
+
if (section) {
|
|
647
|
+
queryParams.section = section;
|
|
648
|
+
}
|
|
595
649
|
|
|
596
|
-
if (
|
|
597
|
-
|
|
650
|
+
if (force) {
|
|
651
|
+
queryParams.force = force;
|
|
652
|
+
}
|
|
598
653
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
queryParams.section = section;
|
|
602
|
-
}
|
|
654
|
+
if (notificationEmail) {
|
|
655
|
+
queryParams.notification_email = notificationEmail;
|
|
603
656
|
}
|
|
604
657
|
|
|
605
658
|
try {
|
|
606
|
-
|
|
607
|
-
requestUrl = createCatalogUrl(`item/${parameters.id}`, this.options, queryParams);
|
|
608
|
-
} else {
|
|
609
|
-
requestUrl = createCatalogUrl('item', this.options, queryParams);
|
|
610
|
-
}
|
|
659
|
+
requestUrl = createCatalogUrl('variations', this.options, queryParams, 'v2');
|
|
611
660
|
} catch (e) {
|
|
612
661
|
return Promise.reject(e);
|
|
613
662
|
}
|
|
@@ -616,7 +665,8 @@ class Catalog {
|
|
|
616
665
|
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
|
|
617
666
|
|
|
618
667
|
return fetch(requestUrl, {
|
|
619
|
-
method: '
|
|
668
|
+
method: 'DELETE',
|
|
669
|
+
body: JSON.stringify({ variations }),
|
|
620
670
|
headers: {
|
|
621
671
|
'Content-Type': 'application/json',
|
|
622
672
|
...helpers.createAuthHeader(this.options),
|
|
@@ -624,60 +674,73 @@ class Catalog {
|
|
|
624
674
|
signal,
|
|
625
675
|
}).then((response) => {
|
|
626
676
|
if (response.ok) {
|
|
627
|
-
return
|
|
677
|
+
return Promise.resolve();
|
|
628
678
|
}
|
|
629
679
|
|
|
630
680
|
return helpers.throwHttpErrorFromResponse(new Error(), response);
|
|
631
|
-
})
|
|
681
|
+
});
|
|
632
682
|
}
|
|
633
683
|
|
|
634
684
|
/**
|
|
635
|
-
* Retrieves
|
|
685
|
+
* Retrieves variation(s) from index for the given section or specific variation ID
|
|
636
686
|
*
|
|
637
|
-
* @function
|
|
638
|
-
* @param {object} parameters - Additional parameters for
|
|
639
|
-
* @param {string} parameters.section -
|
|
640
|
-
* @param {
|
|
641
|
-
* @param {
|
|
687
|
+
* @function retrieveVariations
|
|
688
|
+
* @param {object} parameters - Additional parameters for variation details
|
|
689
|
+
* @param {string} [parameters.section="Products"] - This indicates which section to operate on within the index
|
|
690
|
+
* @param {string[]} [parameters.ids] - Id(s) of variations to return (1,000 maximum)
|
|
691
|
+
* @param {string} [parameters.itemId] - Parent item id to return descendant variations of
|
|
692
|
+
* @param {number} [parameters.numResultsPerPage=100] - The number of items to return
|
|
693
|
+
* @param {number} [parameters.page=1] - The page of results to return
|
|
642
694
|
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
643
695
|
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
644
696
|
* @returns {Promise}
|
|
645
|
-
* @see https://docs.constructor.io/rest_api/items/
|
|
697
|
+
* @see https://docs.constructor.io/rest_api/items/variations/#retrieve-variations
|
|
646
698
|
* @example
|
|
647
|
-
* constructorio.catalog.
|
|
699
|
+
* constructorio.catalog.retrieveVariations({
|
|
648
700
|
* section: 'Products',
|
|
649
|
-
*
|
|
701
|
+
* numResultsPerPage: 50,
|
|
702
|
+
* page: 2,
|
|
703
|
+
* });
|
|
704
|
+
* @example
|
|
705
|
+
* constructorio.catalog.retrieveVariations({
|
|
706
|
+
* ids: ['blk_pllvr_hd_001', 'blk_pllvr_hd_002']
|
|
707
|
+
* section: 'Products',
|
|
708
|
+
* numResultsPerPage: 50,
|
|
650
709
|
* page: 2,
|
|
651
710
|
* });
|
|
652
711
|
*/
|
|
653
|
-
|
|
654
|
-
|
|
712
|
+
retrieveVariations(parameters = {}, networkParameters = {}) {
|
|
713
|
+
let queryParams = {};
|
|
655
714
|
let requestUrl;
|
|
656
715
|
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
657
716
|
const controller = new AbortController();
|
|
658
717
|
const { signal } = controller;
|
|
718
|
+
const { ids, itemId, section, numResultsPerPage, page } = parameters;
|
|
659
719
|
|
|
660
|
-
|
|
661
|
-
const { num_results_per_page: numResultsPerPage, page, section } = parameters;
|
|
720
|
+
queryParams = {};
|
|
662
721
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
}
|
|
722
|
+
if (ids) {
|
|
723
|
+
queryParams.id = ids;
|
|
724
|
+
}
|
|
667
725
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
}
|
|
726
|
+
if (itemId) {
|
|
727
|
+
queryParams.item_id = itemId;
|
|
728
|
+
}
|
|
672
729
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
730
|
+
if (section) {
|
|
731
|
+
queryParams.section = section;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (page) {
|
|
735
|
+
queryParams.page = page;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (numResultsPerPage) {
|
|
739
|
+
queryParams.num_results_per_page = numResultsPerPage;
|
|
677
740
|
}
|
|
678
741
|
|
|
679
742
|
try {
|
|
680
|
-
requestUrl = createCatalogUrl('
|
|
743
|
+
requestUrl = createCatalogUrl('variations', this.options, queryParams, 'v2');
|
|
681
744
|
} catch (e) {
|
|
682
745
|
return Promise.reject(e);
|
|
683
746
|
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/* eslint-disable object-curly-newline, no-underscore-dangle */
|
|
2
|
+
const qs = require('qs');
|
|
3
|
+
const nodeFetch = require('node-fetch').default;
|
|
4
|
+
const helpers = require('../utils/helpers');
|
|
5
|
+
|
|
6
|
+
// Create URL from supplied quizId and parameters
|
|
7
|
+
// eslint-disable-next-line max-params
|
|
8
|
+
function createQuizUrl(quizId, parameters, userParameters, options, path) {
|
|
9
|
+
const {
|
|
10
|
+
apiKey,
|
|
11
|
+
version,
|
|
12
|
+
} = options;
|
|
13
|
+
const {
|
|
14
|
+
sessionId,
|
|
15
|
+
clientId,
|
|
16
|
+
userId,
|
|
17
|
+
segments,
|
|
18
|
+
} = userParameters;
|
|
19
|
+
const serviceUrl = 'https://quizzes.cnstrc.com';
|
|
20
|
+
let queryParams = { c: version };
|
|
21
|
+
let answersParamString = '';
|
|
22
|
+
|
|
23
|
+
queryParams.key = apiKey;
|
|
24
|
+
queryParams.i = clientId;
|
|
25
|
+
queryParams.s = sessionId;
|
|
26
|
+
|
|
27
|
+
// Pull user segments from options
|
|
28
|
+
if (segments && segments.length) {
|
|
29
|
+
queryParams.us = segments;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Pull user id from options
|
|
33
|
+
if (userId) {
|
|
34
|
+
queryParams.ui = userId;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Validate quiz id is provided
|
|
38
|
+
if (!quizId || typeof quizId !== 'string') {
|
|
39
|
+
throw new Error('quizId is a required parameter of type string');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (path === 'finalize' && (typeof parameters.answers !== 'object' || !Array.isArray(parameters.answers) || parameters.answers.length === 0)) {
|
|
43
|
+
throw new Error('answers is a required parameter of type array');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (parameters) {
|
|
47
|
+
const { section, answers, versionId } = parameters;
|
|
48
|
+
|
|
49
|
+
// Pull section from parameters
|
|
50
|
+
if (section) {
|
|
51
|
+
queryParams.section = section;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Pull version_id from parameters
|
|
55
|
+
if (versionId) {
|
|
56
|
+
queryParams.version_id = versionId;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Pull answers from parameters and transform
|
|
60
|
+
if (answers) {
|
|
61
|
+
answers.forEach((ans) => {
|
|
62
|
+
answersParamString += `&${qs.stringify({ a: ans }, { arrayFormat: 'comma' })}`;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
queryParams._dt = Date.now();
|
|
68
|
+
queryParams = helpers.cleanParams(queryParams);
|
|
69
|
+
|
|
70
|
+
const queryString = qs.stringify(queryParams, { indices: false });
|
|
71
|
+
|
|
72
|
+
return `${serviceUrl}/v1/quizzes/${encodeURIComponent(quizId)}/${encodeURIComponent(path)}/?${queryString}${answersParamString}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Interface to quiz related API calls
|
|
77
|
+
*
|
|
78
|
+
* @module quizzes
|
|
79
|
+
* @inner
|
|
80
|
+
* @returns {object}
|
|
81
|
+
*/
|
|
82
|
+
class Quizzes {
|
|
83
|
+
constructor(options) {
|
|
84
|
+
this.options = options || {};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Retrieve quiz question from API
|
|
89
|
+
*
|
|
90
|
+
* @function getQuizNextQuestion
|
|
91
|
+
* @description Retrieve quiz question from Constructor.io API
|
|
92
|
+
* @param {string} id - The identifier of the quiz
|
|
93
|
+
* @param {string} [parameters] - Additional parameters to refine result set
|
|
94
|
+
* @param {string} [parameters.section] - Product catalog section
|
|
95
|
+
* @param {array} [parameters.answers] - An array for answers in the format [[1,2],[1]]
|
|
96
|
+
* @param {string} [parameters.versionId] - Version identifier for the quiz.
|
|
97
|
+
* @param {object} [userParameters] - Parameters relevant to the user request
|
|
98
|
+
* @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
|
|
99
|
+
* @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
|
|
100
|
+
* @param {string} [userParameters.userId] - User ID, utilized to personalize results
|
|
101
|
+
* @param {string} [userParameters.segments] - User segments
|
|
102
|
+
* @param {string} [userParameters.userIp] - Origin user IP, from client
|
|
103
|
+
* @param {string} [userParameters.userAgent] - Origin user agent, from client
|
|
104
|
+
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
105
|
+
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
106
|
+
* @returns {Promise}
|
|
107
|
+
* @see https://docs.constructor.io/rest_api/quiz/using_quizzes/#answering-a-quiz
|
|
108
|
+
* @example
|
|
109
|
+
* constructorio.quizzes.getQuizNextQuestion('quizId', {
|
|
110
|
+
* answers: [[1,2],[1]],
|
|
111
|
+
* section: '123',
|
|
112
|
+
* versionId: '123'
|
|
113
|
+
* });
|
|
114
|
+
*/
|
|
115
|
+
getQuizNextQuestion(quizId, parameters, userParameters = {}, networkParameters = {}) {
|
|
116
|
+
const headers = {};
|
|
117
|
+
let requestUrl;
|
|
118
|
+
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
const { signal } = controller;
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
requestUrl = createQuizUrl(quizId, parameters, userParameters, this.options, 'next');
|
|
124
|
+
} catch (e) {
|
|
125
|
+
return Promise.reject(e);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Append security token as 'x-cnstrc-token' if available
|
|
129
|
+
if (this.options.securityToken && typeof this.options.securityToken === 'string') {
|
|
130
|
+
headers['x-cnstrc-token'] = this.options.securityToken;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Append user IP as 'X-Forwarded-For' if available
|
|
134
|
+
if (userParameters.userIp && typeof userParameters.userIp === 'string') {
|
|
135
|
+
headers['X-Forwarded-For'] = userParameters.userIp;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Append user agent as 'User-Agent' if available
|
|
139
|
+
if (userParameters.userAgent && typeof userParameters.userAgent === 'string') {
|
|
140
|
+
headers['User-Agent'] = userParameters.userAgent;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Handle network timeout if specified
|
|
144
|
+
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
|
|
145
|
+
|
|
146
|
+
return fetch(requestUrl, { headers, signal })
|
|
147
|
+
.then((response) => {
|
|
148
|
+
if (response.ok) {
|
|
149
|
+
return response.json();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return helpers.throwHttpErrorFromResponse(new Error(), response);
|
|
153
|
+
})
|
|
154
|
+
.then((json) => {
|
|
155
|
+
if (json.version_id) {
|
|
156
|
+
return json;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
throw new Error('getQuizNextQuestion response data is malformed');
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Retrieves filter expression and recommendation URL from given answers
|
|
165
|
+
*
|
|
166
|
+
* @function getQuizResults
|
|
167
|
+
* @description Retrieve quiz recommendation and filter expression from Constructor.io API
|
|
168
|
+
* @param {string} id - The identifier of the quiz
|
|
169
|
+
* @param {string} [parameters] - Additional parameters to refine result set
|
|
170
|
+
* @param {string} [parameters.section] - Product catalog section
|
|
171
|
+
* @param {array} [parameters.answers] - An array of answers in the format [[1,2],[1]]
|
|
172
|
+
* @param {string} [parameters.versionId] - Specific version identifier for the quiz
|
|
173
|
+
* @param {object} [userParameters] - Parameters relevant to the user request
|
|
174
|
+
* @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
|
|
175
|
+
* @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
|
|
176
|
+
* @param {string} [userParameters.userId] - User ID, utilized to personalize results
|
|
177
|
+
* @param {string} [userParameters.segments] - User segments
|
|
178
|
+
* @param {string} [userParameters.userIp] - Origin user IP, from client
|
|
179
|
+
* @param {string} [userParameters.userAgent] - Origin user agent, from client
|
|
180
|
+
* @param {object} [networkParameters] - Parameters relevant to the network request
|
|
181
|
+
* @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
|
|
182
|
+
* @returns {Promise}
|
|
183
|
+
* @see https://docs.constructor.io/rest_api/quiz/using_quizzes/#completing-the-quiz
|
|
184
|
+
* @example
|
|
185
|
+
* constructorio.quizzes.getQuizResults('quizId', {
|
|
186
|
+
* answers: [[1,2],[1]],
|
|
187
|
+
* section: '123',
|
|
188
|
+
* versionId: '123'
|
|
189
|
+
* });
|
|
190
|
+
*/
|
|
191
|
+
getQuizResults(quizId, parameters, userParameters = {}, networkParameters = {}) {
|
|
192
|
+
let requestUrl;
|
|
193
|
+
const headers = {};
|
|
194
|
+
const fetch = (this.options && this.options.fetch) || nodeFetch;
|
|
195
|
+
const controller = new AbortController();
|
|
196
|
+
const { signal } = controller;
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
requestUrl = createQuizUrl(quizId, parameters, userParameters, this.options, 'finalize');
|
|
200
|
+
} catch (e) {
|
|
201
|
+
return Promise.reject(e);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Append security token as 'x-cnstrc-token' if available
|
|
205
|
+
if (this.options.securityToken && typeof this.options.securityToken === 'string') {
|
|
206
|
+
headers['x-cnstrc-token'] = this.options.securityToken;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Append user IP as 'X-Forwarded-For' if available
|
|
210
|
+
if (userParameters.userIp && typeof userParameters.userIp === 'string') {
|
|
211
|
+
headers['X-Forwarded-For'] = userParameters.userIp;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Append user agent as 'User-Agent' if available
|
|
215
|
+
if (userParameters.userAgent && typeof userParameters.userAgent === 'string') {
|
|
216
|
+
headers['User-Agent'] = userParameters.userAgent;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Handle network timeout if specified
|
|
220
|
+
helpers.applyNetworkTimeout(this.options, networkParameters, controller);
|
|
221
|
+
|
|
222
|
+
return fetch(requestUrl, { headers, signal })
|
|
223
|
+
.then((response) => {
|
|
224
|
+
if (response.ok) {
|
|
225
|
+
return response.json();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return helpers.throwHttpErrorFromResponse(new Error(), response);
|
|
229
|
+
})
|
|
230
|
+
.then((json) => {
|
|
231
|
+
if (json.version_id) {
|
|
232
|
+
return json;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
throw new Error('getQuizResults response data is malformed');
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
module.exports = Quizzes;
|
package/src/utils/helpers.js
CHANGED
|
@@ -47,7 +47,7 @@ const utils = {
|
|
|
47
47
|
applyNetworkTimeout: (options = {}, networkParameters = {}, controller = undefined) => {
|
|
48
48
|
const optionsTimeout = options && options.networkParameters && options.networkParameters.timeout;
|
|
49
49
|
const networkParametersTimeout = networkParameters && networkParameters.timeout;
|
|
50
|
-
const timeout =
|
|
50
|
+
const timeout = networkParametersTimeout || optionsTimeout;
|
|
51
51
|
|
|
52
52
|
if (typeof timeout === 'number') {
|
|
53
53
|
setTimeout(() => controller.abort(), timeout);
|