diff --git a/src/index.ts b/src/index.ts index 0a60201..056229a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,4 @@ export * from './lib/contentstack-error'; export * from './lib/api-error'; export * from './lib/request'; export * from './lib/retryPolicy/delivery-sdk-handlers'; +export * from './lib/error-messages'; diff --git a/src/lib/api-error.ts b/src/lib/api-error.ts index cc35928..063c0e5 100644 --- a/src/lib/api-error.ts +++ b/src/lib/api-error.ts @@ -1,3 +1,5 @@ +import { ERROR_MESSAGES } from './error-messages'; + /** * Custom error class for API errors with optimized error handling */ @@ -27,10 +29,10 @@ export class APIError extends Error { return APIError.fromResponseData(err.response.data, err.response.status); } else if (err.message) { // For network errors or other non-HTTP errors - return new APIError(err.message, err.code || 'NETWORK_ERROR', 0); + return new APIError(err.message, err.code || ERROR_MESSAGES.ERROR_CODES.NETWORK_ERROR, 0); } else { // Fallback for unknown errors - return new APIError('Unknown error occurred', 'UNKNOWN_ERROR', 0); + return new APIError(ERROR_MESSAGES.API.UNKNOWN_ERROR, ERROR_MESSAGES.ERROR_CODES.UNKNOWN_ERROR, 0); } } @@ -58,7 +60,7 @@ export class APIError extends Error { if (responseData.message) return responseData.message; if (responseData.error) return responseData.error; if (typeof responseData === 'string') return responseData; - return 'Request failed'; + return ERROR_MESSAGES.API.REQUEST_FAILED(); } /** diff --git a/src/lib/contentstack-core.ts b/src/lib/contentstack-core.ts index d1f18ef..15a1ac9 100644 --- a/src/lib/contentstack-core.ts +++ b/src/lib/contentstack-core.ts @@ -2,6 +2,7 @@ import { cloneDeep } from 'lodash'; import { serialize } from './param-serializer'; import axios, { AxiosRequestHeaders, getAdapter } from 'axios'; import { AxiosInstance, HttpClientParams } from './types'; +import { ERROR_MESSAGES } from './error-messages'; export function httpClient(options: HttpClientParams): AxiosInstance { const defaultConfig = { @@ -17,12 +18,12 @@ export function httpClient(options: HttpClientParams): AxiosInstance { if (level === 'error') { if (data) { const title = [data.name, data.message].filter((a) => a).join(' - '); - console.error(`[error] ${title}`); + console.error(ERROR_MESSAGES.CONSOLE.ERROR_WITH_TITLE(title)); } return; } if (data !== undefined) { - console.log(`[${level}] ${data}`); + console.log(ERROR_MESSAGES.CONSOLE.LEVEL_WITH_DATA(level, data)); } }, retryCondition: (error: any) => { diff --git a/src/lib/error-messages.ts b/src/lib/error-messages.ts new file mode 100644 index 0000000..10258df --- /dev/null +++ b/src/lib/error-messages.ts @@ -0,0 +1,43 @@ +/** + * Centralized Error Messages + * + * This file contains all error messages used throughout the contentstack-js-core SDK. + * Centralizing error messages makes them easier to maintain, review, and localize. + */ + +export const ERROR_MESSAGES = { + // Console Logging Messages + CONSOLE: { + ERROR_WITH_TITLE: (title: string) => `Error: ${title}. Review the error details and try again.`, + LEVEL_WITH_DATA: (level: string, data: any) => `${level}: ${data}. Review the details and try again.`, + }, + + // API Error Messages + API: { + NETWORK_ERROR: 'Network error occurred. Please check your internet connection and try again.', + UNKNOWN_ERROR: 'An unknown error occurred. Please try again or contact support if the issue persists.', + REQUEST_FAILED: (status?: number) => + status + ? `Request failed with status ${status}. Please review your request and try again.` + : 'Request failed. Please review your request and try again.', + }, + + // Request Handler Messages + REQUEST: { + HOST_REQUIRED_FOR_LIVE_PREVIEW: 'Host is required for live preview. Please provide a valid host parameter in the live_preview configuration.', + }, + + // Retry Policy Messages + RETRY: { + TIMEOUT_EXCEEDED: (timeout: number) => + `Request timeout of ${timeout}ms exceeded. Please try again or increase the timeout value in your configuration.`, + }, + + // Error Codes + ERROR_CODES: { + NETWORK_ERROR: 'NETWORK_ERROR', + UNKNOWN_ERROR: 'UNKNOWN_ERROR', + TIMEOUT: 408, + }, +} as const; + diff --git a/src/lib/request.ts b/src/lib/request.ts index a40ccfb..4326c63 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -1,6 +1,7 @@ import { AxiosInstance } from './types'; import { serialize } from './param-serializer'; import { APIError } from './api-error'; +import { ERROR_MESSAGES } from './error-messages'; /** * Handles array parameters properly with & separators @@ -73,7 +74,7 @@ export async function getData(instance: AxiosInstance, url: string, data?: any) // adds protocol so host is replaced and not appended if (livePreviewParams.live_preview && livePreviewParams.live_preview !== 'init') { if (!livePreviewParams.host) { - throw new Error('Host is required for live preview'); + throw new Error(ERROR_MESSAGES.REQUEST.HOST_REQUIRED_FOR_LIVE_PREVIEW); } url = (livePreviewParams.host.startsWith('https://') ? '' : 'https://') + livePreviewParams.host + url; } diff --git a/src/lib/retryPolicy/delivery-sdk-handlers.ts b/src/lib/retryPolicy/delivery-sdk-handlers.ts index 9793cf6..0413646 100644 --- a/src/lib/retryPolicy/delivery-sdk-handlers.ts +++ b/src/lib/retryPolicy/delivery-sdk-handlers.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-throw-literal */ import axios, { InternalAxiosRequestConfig, AxiosResponse, AxiosInstance } from 'axios'; +import { ERROR_MESSAGES } from '../error-messages'; declare module 'axios' { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -35,8 +36,8 @@ export const retryResponseErrorHandler = (error: any, config: any, axiosInstance if (!response) { if (error.code === 'ECONNABORTED') { const customError = { - error_message: `Timeout of ${config.timeout}ms exceeded`, - error_code: 408, + error_message: ERROR_MESSAGES.RETRY.TIMEOUT_EXCEEDED(config.timeout), + error_code: ERROR_MESSAGES.ERROR_CODES.TIMEOUT, errors: null, }; throw customError; // Throw customError object diff --git a/test/api-error.spec.ts b/test/api-error.spec.ts index 5c765a6..fe6ca84 100644 --- a/test/api-error.spec.ts +++ b/test/api-error.spec.ts @@ -74,7 +74,7 @@ describe('APIError', () => { const error = APIError.fromAxiosError(axiosError); expect(error).toBeInstanceOf(APIError); - expect(error.error_message).toBe('Unknown error occurred'); + expect(error.error_message).toBe('An unknown error occurred. Please try again or contact support if the issue persists.'); expect(error.error_code).toBe('UNKNOWN_ERROR'); expect(error.status).toBe(0); }); @@ -169,7 +169,7 @@ describe('APIError', () => { const error = APIError.fromResponseData(responseData, 500); expect(error).toBeInstanceOf(APIError); - expect(error.error_message).toBe('Request failed'); + expect(error.error_message).toBe('Request failed. Please review your request and try again.'); expect(error.error_code).toBe(500); expect(error.status).toBe(500); }); diff --git a/test/contentstack-core.spec.ts b/test/contentstack-core.spec.ts index 1cfd3ab..e69a7d3 100644 --- a/test/contentstack-core.spec.ts +++ b/test/contentstack-core.spec.ts @@ -17,7 +17,7 @@ describe('contentstackCore', () => { const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(); httpClient({}).defaults.logHandler('error', error); - expect(consoleErrorSpy).toHaveBeenCalledWith('[error] Error - Something went wrong'); + expect(consoleErrorSpy).toHaveBeenCalledWith('Error: Error - Something went wrong. Review the error details and try again.'); consoleErrorSpy.mockRestore(); }); @@ -36,7 +36,7 @@ describe('contentstackCore', () => { httpClient({}).defaults.logHandler('info', 'Some message'); - expect(consoleLogSpy).toHaveBeenCalledWith('[info] Some message'); + expect(consoleLogSpy).toHaveBeenCalledWith('info: Some message. Review the details and try again.'); consoleLogSpy.mockRestore(); }); diff --git a/test/retryPolicy/delivery-sdk-handlers.spec.ts b/test/retryPolicy/delivery-sdk-handlers.spec.ts index 659cfe8..be464de 100644 --- a/test/retryPolicy/delivery-sdk-handlers.spec.ts +++ b/test/retryPolicy/delivery-sdk-handlers.spec.ts @@ -83,7 +83,7 @@ describe('retryResponseErrorHandler', () => { expect(err).toEqual( expect.objectContaining({ error_code: 408, - error_message: `Timeout of ${config.timeout}ms exceeded`, + error_message: `Request timeout of ${config.timeout}ms exceeded. Please try again or increase the timeout value in your configuration.`, errors: null, }) );