Skip to content

Commit cb39921

Browse files
committed
feat: centralize error messages for better maintainability
- Created centralized error-messages.ts file with all error messages organized by category - Updated all source files to use centralized error messages - Improved error messages with clearer descriptions and actionable guidance - Updated tests to match new improved error messages - All 118 tests passing with 100% coverage Error messages now include: - Console logging messages with better context - API error messages with helpful guidance - Request handler messages with configuration hints - Retry policy messages with actionable suggestions
1 parent 5691607 commit cb39921

File tree

10 files changed

+63
-27
lines changed

10 files changed

+63
-27
lines changed

package-lock.json

Lines changed: 1 addition & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export * from './lib/contentstack-error';
44
export * from './lib/api-error';
55
export * from './lib/request';
66
export * from './lib/retryPolicy/delivery-sdk-handlers';
7+
export * from './lib/error-messages';

src/lib/api-error.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { ERROR_MESSAGES } from './error-messages';
2+
13
/**
24
* Custom error class for API errors with optimized error handling
35
*/
@@ -27,10 +29,10 @@ export class APIError extends Error {
2729
return APIError.fromResponseData(err.response.data, err.response.status);
2830
} else if (err.message) {
2931
// For network errors or other non-HTTP errors
30-
return new APIError(err.message, err.code || 'NETWORK_ERROR', 0);
32+
return new APIError(err.message, err.code || ERROR_MESSAGES.ERROR_CODES.NETWORK_ERROR, 0);
3133
} else {
3234
// Fallback for unknown errors
33-
return new APIError('Unknown error occurred', 'UNKNOWN_ERROR', 0);
35+
return new APIError(ERROR_MESSAGES.API.UNKNOWN_ERROR, ERROR_MESSAGES.ERROR_CODES.UNKNOWN_ERROR, 0);
3436
}
3537
}
3638

@@ -58,7 +60,7 @@ export class APIError extends Error {
5860
if (responseData.message) return responseData.message;
5961
if (responseData.error) return responseData.error;
6062
if (typeof responseData === 'string') return responseData;
61-
return 'Request failed';
63+
return ERROR_MESSAGES.API.REQUEST_FAILED();
6264
}
6365

6466
/**

src/lib/contentstack-core.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { cloneDeep } from 'lodash';
22
import { serialize } from './param-serializer';
33
import axios, { AxiosRequestHeaders, getAdapter } from 'axios';
44
import { AxiosInstance, HttpClientParams } from './types';
5+
import { ERROR_MESSAGES } from './error-messages';
56

67
export function httpClient(options: HttpClientParams): AxiosInstance {
78
const defaultConfig = {
@@ -17,12 +18,12 @@ export function httpClient(options: HttpClientParams): AxiosInstance {
1718
if (level === 'error') {
1819
if (data) {
1920
const title = [data.name, data.message].filter((a) => a).join(' - ');
20-
console.error(`[error] ${title}`);
21+
console.error(ERROR_MESSAGES.CONSOLE.ERROR_WITH_TITLE(title));
2122
}
2223
return;
2324
}
2425
if (data !== undefined) {
25-
console.log(`[${level}] ${data}`);
26+
console.log(ERROR_MESSAGES.CONSOLE.LEVEL_WITH_DATA(level, data));
2627
}
2728
},
2829
retryCondition: (error: any) => {

src/lib/error-messages.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Centralized Error Messages
3+
*
4+
* This file contains all error messages used throughout the contentstack-js-core SDK.
5+
* Centralizing error messages makes them easier to maintain, review, and localize.
6+
*/
7+
8+
export const ERROR_MESSAGES = {
9+
// Console Logging Messages
10+
CONSOLE: {
11+
ERROR_WITH_TITLE: (title: string) => `Error: ${title}. Review the error details and try again.`,
12+
LEVEL_WITH_DATA: (level: string, data: any) => `${level}: ${data}. Review the details and try again.`,
13+
},
14+
15+
// API Error Messages
16+
API: {
17+
NETWORK_ERROR: 'Network error occurred. Please check your internet connection and try again.',
18+
UNKNOWN_ERROR: 'An unknown error occurred. Please try again or contact support if the issue persists.',
19+
REQUEST_FAILED: (status?: number) =>
20+
status
21+
? `Request failed with status ${status}. Please review your request and try again.`
22+
: 'Request failed. Please review your request and try again.',
23+
},
24+
25+
// Request Handler Messages
26+
REQUEST: {
27+
HOST_REQUIRED_FOR_LIVE_PREVIEW: 'Host is required for live preview. Please provide a valid host parameter in the live_preview configuration.',
28+
},
29+
30+
// Retry Policy Messages
31+
RETRY: {
32+
TIMEOUT_EXCEEDED: (timeout: number) =>
33+
`Request timeout of ${timeout}ms exceeded. Please try again or increase the timeout value in your configuration.`,
34+
},
35+
36+
// Error Codes
37+
ERROR_CODES: {
38+
NETWORK_ERROR: 'NETWORK_ERROR',
39+
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
40+
TIMEOUT: 408,
41+
},
42+
} as const;
43+

src/lib/request.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { AxiosInstance } from './types';
22
import { serialize } from './param-serializer';
33
import { APIError } from './api-error';
4+
import { ERROR_MESSAGES } from './error-messages';
45

56
/**
67
* Handles array parameters properly with & separators
@@ -63,7 +64,7 @@ export async function getData(instance: AxiosInstance, url: string, data?: any)
6364
// adds protocol so host is replaced and not appended
6465
if (livePreviewParams.live_preview && livePreviewParams.live_preview !== 'init') {
6566
if (!livePreviewParams.host) {
66-
throw new Error('Host is required for live preview');
67+
throw new Error(ERROR_MESSAGES.REQUEST.HOST_REQUIRED_FOR_LIVE_PREVIEW);
6768
}
6869
url = (livePreviewParams.host.startsWith('https://') ? '' : 'https://') + livePreviewParams.host + url;
6970
}

src/lib/retryPolicy/delivery-sdk-handlers.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-throw-literal */
22
import axios, { InternalAxiosRequestConfig, AxiosResponse, AxiosInstance } from 'axios';
3+
import { ERROR_MESSAGES } from '../error-messages';
34

45
declare module 'axios' {
56
// eslint-disable-next-line @typescript-eslint/naming-convention
@@ -35,8 +36,8 @@ export const retryResponseErrorHandler = (error: any, config: any, axiosInstance
3536
if (!response) {
3637
if (error.code === 'ECONNABORTED') {
3738
const customError = {
38-
error_message: `Timeout of ${config.timeout}ms exceeded`,
39-
error_code: 408,
39+
error_message: ERROR_MESSAGES.RETRY.TIMEOUT_EXCEEDED(config.timeout),
40+
error_code: ERROR_MESSAGES.ERROR_CODES.TIMEOUT,
4041
errors: null,
4142
};
4243
throw customError; // Throw customError object

test/api-error.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ describe('APIError', () => {
7474
const error = APIError.fromAxiosError(axiosError);
7575

7676
expect(error).toBeInstanceOf(APIError);
77-
expect(error.error_message).toBe('Unknown error occurred');
77+
expect(error.error_message).toBe('An unknown error occurred. Please try again or contact support if the issue persists.');
7878
expect(error.error_code).toBe('UNKNOWN_ERROR');
7979
expect(error.status).toBe(0);
8080
});
@@ -169,7 +169,7 @@ describe('APIError', () => {
169169
const error = APIError.fromResponseData(responseData, 500);
170170

171171
expect(error).toBeInstanceOf(APIError);
172-
expect(error.error_message).toBe('Request failed');
172+
expect(error.error_message).toBe('Request failed. Please review your request and try again.');
173173
expect(error.error_code).toBe(500);
174174
expect(error.status).toBe(500);
175175
});

test/contentstack-core.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ describe('contentstackCore', () => {
1717
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
1818
httpClient({}).defaults.logHandler('error', error);
1919

20-
expect(consoleErrorSpy).toHaveBeenCalledWith('[error] Error - Something went wrong');
20+
expect(consoleErrorSpy).toHaveBeenCalledWith('Error: Error - Something went wrong. Review the error details and try again.');
2121

2222
consoleErrorSpy.mockRestore();
2323
});
@@ -36,7 +36,7 @@ describe('contentstackCore', () => {
3636

3737
httpClient({}).defaults.logHandler('info', 'Some message');
3838

39-
expect(consoleLogSpy).toHaveBeenCalledWith('[info] Some message');
39+
expect(consoleLogSpy).toHaveBeenCalledWith('info: Some message. Review the details and try again.');
4040

4141
consoleLogSpy.mockRestore();
4242
});

test/retryPolicy/delivery-sdk-handlers.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ describe('retryResponseErrorHandler', () => {
8383
expect(err).toEqual(
8484
expect.objectContaining({
8585
error_code: 408,
86-
error_message: `Timeout of ${config.timeout}ms exceeded`,
86+
error_message: `Request timeout of ${config.timeout}ms exceeded. Please try again or increase the timeout value in your configuration.`,
8787
errors: null,
8888
})
8989
);

0 commit comments

Comments
 (0)