Skip to content

Commit 716dad3

Browse files
committed
[sc-11931] handle POST request payload
1 parent e7c3f54 commit 716dad3

File tree

4 files changed

+179
-40
lines changed

4 files changed

+179
-40
lines changed

src/apifetch.ts

Lines changed: 158 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import 'es6-promise/auto';
22
import { apiInstance, RESPONSE_BAD_REQUEST, RESPONSE_SERVER_ERROR } from './api';
3-
import { Settings } from './settings';
3+
import { Settings, SortByOptions, SortOrder, SortOrderOptions } from './settings';
44
import { AxiosResponse } from 'axios';
5+
import { isEmptyObject } from './util';
56

67
interface RecommendOptions {
78
type: 'RELATED_ITEMS' | 'FREQUENTLY_BOUGHT_TOGETHER';
@@ -121,6 +122,7 @@ const executeApiFetch: ExecuteApiFetch = function (
121122

122123
let keyword = '';
123124
let queryParamsString = '';
125+
let requestPayloadObject = {};
124126

125127
// API Path (eq. /search, /suggest, /autocomplete/document-field)
126128
let apiEndpoint: string | null = null;
@@ -155,6 +157,7 @@ const executeApiFetch: ExecuteApiFetch = function (
155157
}
156158
}
157159

160+
// GET Parameters
158161
queryParamsString =
159162
settingToQueryParam(settings?.lang, 'lang') +
160163
settingToQueryParam(fuzzy, 'fuzzy') +
@@ -176,13 +179,48 @@ const executeApiFetch: ExecuteApiFetch = function (
176179
settingToQueryParam(settings?.searchOperator, 'defaultOperator') +
177180
settingToQueryParam(settings?.analyticsTag, 'analyticsTag');
178181

182+
// POST Parameters
183+
184+
requestPayloadObject = {
185+
...requestPayloadObject,
186+
language: settings?.lang,
187+
fuzzy: fuzzy !== true && fuzzy !== false ? fuzzy : JSON.stringify(fuzzy),
188+
// fuzzy: fuzzy,
189+
collectAnalytics: settings?.collectAnalytics,
190+
postfixWildcard: settings?.postfixWildcard,
191+
categories: settings?.categories ? settings?.categories.split(',') : undefined,
192+
priceFromCents: settings?.priceFromCents ? parseFloat(settings?.priceFromCents) : undefined,
193+
priceToCents: settings?.priceToCents ? parseFloat(settings?.priceToCents) : undefined,
194+
dateFrom: settings?.dateFrom,
195+
dateTo: settings?.dateTo,
196+
paging: {
197+
page: settings?.paging.page ? settings?.paging.page : 1,
198+
pageSize: settings?.paging.pageSize ? settings?.paging.pageSize : 10,
199+
shuffleAndLimitTo: settings?.shuffleAndLimitTo || undefined,
200+
sortByField: settings?.paging.sortBy,
201+
sortOrder: settings?.paging.sortOrder
202+
},
203+
jwt: settings?.jwt,
204+
resultType: settings?.resultType,
205+
userToken: settings?.userToken || undefined,
206+
numFacets: settings?.numFacets,
207+
cacheResponseWithTtlSeconds: settings?.cacheResponseTime || undefined,
208+
defaultOperator: settings?.searchOperator || undefined,
209+
analyticsTag: settings?.analyticsTag
210+
};
211+
179212
// Add sortBy and sortOrder
180-
if (Array.isArray(settings?.paging.sortBy)) {
213+
if (Array.isArray(settings?.paging.sortBy) && settings?.paging.sortBy.length > 1) {
214+
const sortByValues: SortByOptions = [];
215+
const sortOrderValues: SortOrderOptions[] = [];
181216
settings?.paging.sortBy.forEach(function (value, index) {
182217
queryParamsString =
183218
queryParamsString +
184219
settingToQueryParam(value, 'sort') +
185220
settingToQueryParam(settings?.paging.sortOrder[index], 'order');
221+
222+
sortByValues.push(value);
223+
sortOrderValues.push(settings?.paging.sortOrder[index] as SortOrder);
186224
});
187225
} else {
188226
queryParamsString =
@@ -193,16 +231,34 @@ const executeApiFetch: ExecuteApiFetch = function (
193231

194232
// Add custom field filters
195233
if (settings?.customFieldFilters) {
234+
const customFieldFiltersValues: any = {};
196235
for (let i = 0; i < settings?.customFieldFilters.length; i++) {
197236
queryParamsString = queryParamsString + '&customField=' + settings?.customFieldFilters[i];
237+
238+
var decodedCustomFieldFilter = decodeURIComponent(settings?.customFieldFilters[i]);
239+
var customFieldFilterPair = decodedCustomFieldFilter.split('=');
240+
var customFieldName = customFieldFilterPair[0];
241+
var customFieldValue = customFieldFilterPair[1];
242+
customFieldFiltersValues[customFieldName] = customFieldValue;
198243
}
244+
245+
requestPayloadObject = {
246+
...requestPayloadObject,
247+
customField: isEmptyObject(customFieldFiltersValues) ? undefined : customFieldFiltersValues
248+
};
199249
}
200250

201251
// Add facet fields
202252
if (settings?.facetFields) {
253+
const facetFieldsValues: string[] = [];
203254
for (let i = 0; i < settings?.facetFields.length; i++) {
204255
queryParamsString = queryParamsString + '&facet=' + settings?.facetFields[i];
256+
facetFieldsValues.push(settings?.facetFields[i]);
205257
}
258+
requestPayloadObject = {
259+
...requestPayloadObject,
260+
facet: facetFieldsValues.length > 0 ? facetFieldsValues : undefined
261+
};
206262
}
207263

208264
// Range facets
@@ -211,6 +267,10 @@ const executeApiFetch: ExecuteApiFetch = function (
211267
queryParamsString +
212268
'&rangeFacets=' +
213269
encodeURIComponent(JSON.stringify(settings?.rangeFacets));
270+
requestPayloadObject = {
271+
...requestPayloadObject,
272+
rangeFacets: settings?.rangeFacets
273+
};
214274
}
215275

216276
// Hierarchical facets
@@ -219,32 +279,56 @@ const executeApiFetch: ExecuteApiFetch = function (
219279
queryParamsString +
220280
'&hierarchicalFacets=' +
221281
encodeURIComponent(JSON.stringify(settings?.hierarchicalFacetSetting));
282+
requestPayloadObject = {
283+
...requestPayloadObject,
284+
hierarchicalFacets: settings?.hierarchicalFacetSetting
285+
};
222286
}
223287

224288
// Stats fields
225289
if (settings?.statsFields) {
290+
const statsFieldsValues: string[] = [];
226291
for (let i = 0; i < settings?.statsFields.length; i++) {
227292
queryParamsString = queryParamsString + '&fieldStat=' + settings?.statsFields[i];
293+
statsFieldsValues.push(settings?.statsFields[i]);
228294
}
295+
requestPayloadObject = {
296+
...requestPayloadObject,
297+
statsFields: statsFieldsValues
298+
};
229299
}
230300

231301
// Personalization events
232302
if (settings?.personalizationEvents && Array.isArray(settings?.personalizationEvents)) {
303+
const personalizationEventsValues: any[] = [];
233304
for (let i = 0; i < settings?.personalizationEvents.length; i++) {
234305
const obj = settings?.personalizationEvents[i];
235306
const key = Object.keys(obj)[0];
236307
queryParamsString =
237308
queryParamsString + '&personalizationEvent=' + encodeURIComponent(key + '=' + obj[key]);
309+
personalizationEventsValues.push(obj);
238310
}
311+
requestPayloadObject = {
312+
...requestPayloadObject,
313+
personalizationEvents: personalizationEventsValues
314+
};
239315
}
240316

241317
// Filter object
242318
if (customFilterObject) {
243319
queryParamsString =
244320
queryParamsString + '&filter=' + encodeURIComponent(JSON.stringify(customFilterObject));
321+
requestPayloadObject = {
322+
...requestPayloadObject,
323+
filter: customFilterObject
324+
};
245325
} else if (settings?.filterObject) {
246326
queryParamsString =
247327
queryParamsString + '&filter=' + encodeURIComponent(JSON.stringify(settings?.filterObject));
328+
requestPayloadObject = {
329+
...requestPayloadObject,
330+
filter: isEmptyObject(settings?.filterObject) ? undefined : settings?.filterObject
331+
};
248332
}
249333

250334
apiEndpoint =
@@ -295,6 +379,12 @@ const executeApiFetch: ExecuteApiFetch = function (
295379
queryParamsString =
296380
settingToQueryParam(settings?.suggestionsSize, 'size') +
297381
settingToQueryParam(settings?.lang, 'language');
382+
requestPayloadObject = {
383+
...requestPayloadObject,
384+
size: settings?.suggestionsSize,
385+
language: settings?.lang
386+
};
387+
298388
keyword = settings?.suggestionsPrefix as string;
299389
apiEndpoint =
300390
'https://' +
@@ -325,6 +415,12 @@ const executeApiFetch: ExecuteApiFetch = function (
325415
'?term=' +
326416
keyword +
327417
queryParamsString;
418+
419+
requestPayloadObject = {
420+
...requestPayloadObject,
421+
source: settings?.autocomplete.field,
422+
size: settings?.autocomplete.size
423+
};
328424
} else if (type === 'recommend') {
329425
if (recommendOptions?.type === 'RELATED_ITEMS') {
330426
queryParamsString = settingToQueryParam(recommendOptions.itemId, 'itemId');
@@ -335,6 +431,12 @@ const executeApiFetch: ExecuteApiFetch = function (
335431
recommendOptions.blockId +
336432
'?' +
337433
queryParamsString;
434+
435+
requestPayloadObject = {
436+
...requestPayloadObject,
437+
itemId: recommendOptions.itemId ? recommendOptions.itemId : undefined,
438+
blockId: recommendOptions.blockId
439+
};
338440
} else if (recommendOptions?.type === 'FREQUENTLY_BOUGHT_TOGETHER') {
339441
queryParamsString = settingToQueryParam(recommendOptions.itemId, 'itemId');
340442
apiPath =
@@ -343,49 +445,69 @@ const executeApiFetch: ExecuteApiFetch = function (
343445
'?configurationKey=' +
344446
recommendOptions.configurationKey +
345447
queryParamsString;
448+
449+
requestPayloadObject = {
450+
...requestPayloadObject,
451+
itemId: recommendOptions.itemId ? recommendOptions.itemId : undefined,
452+
configurationKey: recommendOptions.configurationKey
453+
};
346454
}
347455
apiEndpoint = 'https://' + apiHostname + '/v1/' + apiPath;
348456
}
349457

458+
// Handle API response for all types except ai-answers
350459
if (type !== 'ai-answers') {
351-
apiInstance
352-
.get(apiEndpoint as string)
353-
.then(function (response: AxiosResponse<GenericApiResponse>) {
354-
const json = response.data;
355-
356-
// Search again with fuzzy=true if no hits
357-
if (
358-
type === 'search' &&
359-
settings?.fuzzy === 'retry' &&
360-
json.total_hits === 0 &&
361-
fuzzyRetry !== true
362-
) {
363-
executeApiFetch(apiHostname, sitekey, type, settings, cb, true);
460+
const handleApiResponse = function (response: AxiosResponse<GenericApiResponse>) {
461+
const json = response.data;
462+
463+
// Search again with fuzzy=true if no hits
464+
if (
465+
type === 'search' &&
466+
settings?.fuzzy === 'retry' &&
467+
json.total_hits === 0 &&
468+
fuzzyRetry !== true
469+
) {
470+
executeApiFetch(apiHostname, sitekey, type, settings, cb, true);
471+
} else {
472+
// Cap fuzzy results to one page as quality decreases quickly
473+
if (fuzzyRetry === true) {
474+
json.total_hits = Math.min(
475+
json.total_hits ?? Infinity,
476+
settings?.paging?.pageSize ?? Infinity
477+
);
364478
}
365-
// Fuzzy not "retry" OR fuzzyRetry already returning
366-
else {
367-
// Cap fuzzy results to one page as quality decreases quickly
368-
if (fuzzyRetry === true) {
369-
json.total_hits = Math.min(
370-
json.total_hits ?? Infinity,
371-
settings?.paging?.pageSize ?? Infinity
372-
);
373-
}
374479

375-
// Callback
376-
cb(json);
480+
// Callback
481+
cb(json);
482+
}
483+
};
484+
485+
const handleApiError = function (error: any) {
486+
console.error(error);
487+
cb({
488+
error: {
489+
response: RESPONSE_SERVER_ERROR,
490+
message: 'invalid server response'
377491
}
378-
})
379-
.catch(function (error) {
380-
console.error(error);
381-
382-
cb({
383-
error: {
384-
response: RESPONSE_SERVER_ERROR,
385-
message: 'invalid server response'
386-
}
387-
});
388492
});
493+
};
494+
495+
if (settings?.apiMethod === 'POST' && ['search', 'suggest', 'autocomplete'].includes(type)) {
496+
apiEndpoint = 'https://' + apiHostname + '/v1/' + apiPath + '/' + sitekey;
497+
requestPayloadObject = {
498+
term: keyword,
499+
...requestPayloadObject
500+
};
501+
apiInstance
502+
.post(apiEndpoint, requestPayloadObject)
503+
.then(handleApiResponse)
504+
.catch(handleApiError);
505+
} else {
506+
apiInstance
507+
.get(apiEndpoint as string)
508+
.then(handleApiResponse)
509+
.catch(handleApiError);
510+
}
389511
}
390512
};
391513

src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import SettingsManager, {
1919
SortByOptions,
2020
SortOrderOptions,
2121
FromToRange,
22-
FuzzyMatch
22+
FuzzyMatch,
23+
ApiMethod
2324
} from './settings';
2425

2526
import * as util from './util';
@@ -256,7 +257,7 @@ class AddSearchClient {
256257
this.apiHostname,
257258
this.sitekey,
258259
'recommend',
259-
null,
260+
this.settings.getSettings(),
260261
callback,
261262
false,
262263
null,
@@ -441,6 +442,10 @@ class AddSearchClient {
441442
this.settings.setSearchOperator(operator);
442443
}
443444

445+
setApiMethod(method: ApiMethod): void {
446+
this.settings.setApiMethod(method);
447+
}
448+
444449
sendStatsEvent(type: 'search' | 'click', keyword: string, data: StatsEventPayload): void {
445450
const useUserTokenInCookie =
446451
!this.useStatsSessionId && isPersonalizationTrackingEnabled && isAddSearchCookieConsented;

src/settings.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ export type Settings = {
6666
statsFields?: string[];
6767
numFacets?: number;
6868
shuffleAndLimitTo?: number;
69+
apiMethod?: ApiMethod;
6970
};
7071

72+
export type ApiMethod = 'GET' | 'POST';
73+
7174
class SettingsManager {
7275
private settings: Settings;
7376

@@ -93,7 +96,8 @@ class SettingsManager {
9396
searchOperator: null,
9497
enableLogicalOperators: false,
9598
cacheResponseTime: null,
96-
statsRequestIntercepted: false
99+
statsRequestIntercepted: false,
100+
apiMethod: 'GET'
97101
};
98102
}
99103

@@ -296,6 +300,10 @@ class SettingsManager {
296300
setStatsRequestIntercepted(isIntercepted: boolean): void {
297301
this.settings.statsRequestIntercepted = isIntercepted;
298302
}
303+
304+
setApiMethod(method: ApiMethod): void {
305+
this.settings.apiMethod = method;
306+
}
299307
}
300308

301309
export default SettingsManager;

src/util.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,8 @@ const generateUUID = (): string => {
5353
return uuidv4().replace(/-/g, '');
5454
};
5555

56-
export { isFunction, base64, validateSetPagingParams, generateUUID };
56+
const isEmptyObject = (obj: object): boolean => {
57+
return Object.keys(obj).length === 0;
58+
};
59+
60+
export { isFunction, base64, validateSetPagingParams, generateUUID, isEmptyObject };

0 commit comments

Comments
 (0)