@coveo/platform-client
Version:
The main goal of this package is to provide an easy to configure and straightforward way of querying Coveo Cloud APIs using JavaScript.
143 lines • 5.99 kB
JavaScript
// TODO CDX-1574: remove this polyfill when we bump the minimal supported Node.js version to 22
import 'core-js/actual/json/parse.js';
/**
* Check whether the response status is `204 No Content`.
* @param response
*/
export const isNoContent = (response) => response.status === 204;
/**
* Check whether the response is considered to have any "ok" status code (not just 200).
* @param response
*/
export const isAnyOkStatus = (response) => response.ok;
const noContent = {
canProcess: isNoContent,
process: () => Promise.resolve({}),
};
const success = {
canProcess: isAnyOkStatus,
process: async (response, responseBodyFormat = 'json') => {
if (responseBodyFormat !== 'json') {
return response[responseBodyFormat]();
}
const content = await response.text();
return JSON.parse(content, (_key, value, context) => {
if (typeof value === 'number' && !Number.isSafeInteger(Math.floor(value))) {
return context.source;
}
return value;
});
},
};
/**
* @deprecated Use `success` handler with `responseBodyFormat` `'blob'` instead. Will be removed in version 45
*/
const successBlob = {
canProcess: isAnyOkStatus,
process: async (response) => (await response.blob()),
};
const error = {
canProcess: () => true,
process: async (response) => {
const responseJson = (await response.json());
const platformError = new CoveoPlatformClientError();
Object.assign(platformError, responseJson);
platformError.xRequestId = response.headers.get('X-Request-ID') ?? 'unknown';
platformError.title = responseJson.title ?? getErrorTypeFromAliases(responseJson) ?? 'unknown';
platformError.detail = responseJson.detail ?? getErrorDetailFromAliases(responseJson) ?? 'unknown';
platformError.status = response.status;
throw platformError;
},
};
const blockedByWAF = {
canProcess: (response) => response.headers.get('x-coveo-waf-action') === 'block',
process: (response) => {
const platformError = new CoveoPlatformClientError();
platformError.xRequestId = response.headers.get('X-Request-ID') ?? 'unknown';
platformError.title = 'Request blocked for security reasons';
platformError.detail = 'The web application firewall has identified the request to be potentially malicious.';
platformError.status = response.status;
throw platformError;
},
};
const badGateway = {
canProcess: (response) => response.status === 502,
process: (response) => {
const platformError = new CoveoPlatformClientError();
platformError.xRequestId = response.headers.get('X-Request-ID') ?? 'unknown';
platformError.title = 'Endpoint unreachable';
platformError.detail =
'The service is currently unable to reach the necessary endpoint, likely due to a bad gateway. Please try your request again later.';
platformError.status = response.status;
throw platformError;
},
};
const htmlError = {
canProcess: (response) => response.headers.get('content-type') === 'text/html',
process: async (response) => {
const platformError = new CoveoPlatformClientError();
platformError.xRequestId = response.headers.get('X-Request-ID') ?? 'unknown';
platformError.title =
'Unable to process the request. An issue has occurred with the endpoint, and the system is unable to parse the error.';
platformError.detail = await response.text();
platformError.status = response.status;
throw platformError;
},
};
const errorTypeAliases = ['type', 'errorCode', 'code'];
const getErrorTypeFromAliases = (responseJson) => getErrorPropsFromAliases(responseJson, errorTypeAliases);
const errorDetailAliases = ['message'];
const getErrorDetailFromAliases = (responseJson) => getErrorPropsFromAliases(responseJson, errorDetailAliases);
const getErrorPropsFromAliases = (responseJson, aliasList) => {
for (const alias of aliasList) {
if (alias in responseJson && typeof responseJson[alias] === 'string') {
return responseJson[alias];
}
}
return null;
};
const defaultResponseHandlers = Object.freeze([noContent, success, blockedByWAF, badGateway, htmlError, error]);
export const ResponseHandlers = Object.freeze({
noContent,
success,
successBlob,
blockedByWAF,
badGateway,
htmlError,
error,
});
export default async (response, customHandlers, responseBodyFormat) => {
const handlers = customHandlers?.length ? customHandlers : defaultResponseHandlers;
const handler = handlers.find((candidate) => Object.prototype.hasOwnProperty.call(candidate, 'canProcess') &&
Object.prototype.hasOwnProperty.call(candidate, 'process') &&
candidate.canProcess(response));
if (!handler) {
throw new Error('No suitable response handler found');
}
return await handler.process(response, responseBodyFormat);
};
/**
* Represent errors coming from Coveo's API.
* Follow loosely [RFC-7807](https://www.ietf.org/rfc/rfc7807.html)
*/
export class CoveoPlatformClientError extends Error {
/**
* The HTTP X-Request-ID request header is an optional and unofficial HTTP header, used to trace individual HTTP requests from the client to the server and back again.
* It allows the client and server to correlate each HTTP request.
*/
xRequestId;
/**
* A short, human-readable summary of the problem type.
* It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization
*/
title;
/**
* The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.
*/
status;
/**
* A human-readable explanation specific to this occurrence of the problem.
*/
detail;
}
//# sourceMappingURL=ResponseHandlers.js.map