Skip to content

Commit b2cf073

Browse files
Merge pull request #143 from contentstack/fix/dx-3655
fix: resolve params serialization issue and add api error class for p…
2 parents 3e52e2c + 82143bf commit b2cf073

File tree

7 files changed

+94
-18
lines changed

7 files changed

+94
-18
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## Change log
22

3+
### Version: 1.3.3
4+
#### Date: Oct-27-2025
5+
- Fix: Used common serialize method for query params
6+
37
### Version: 1.3.1
48
#### Date: Sept-01-2025
59
- Fix: Replace URLSearchParams.set() with React Native compatible implementation

package-lock.json

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

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@contentstack/core",
3-
"version": "1.3.2",
3+
"version": "1.3.3",
44
"type": "commonjs",
55
"main": "./dist/cjs/src/index.js",
66
"types": "./dist/cjs/src/index.d.ts",

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './lib/contentstack-core';
22
export * from './lib/types';
33
export * from './lib/contentstack-error';
4+
export * from './lib/api-error';
45
export * from './lib/request';
56
export * from './lib/retryPolicy/delivery-sdk-handlers';

src/lib/api-error.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Custom error class for API errors with optimized error handling
3+
*/
4+
export class APIError extends Error {
5+
public error_code: number | string;
6+
public status: number;
7+
public error_message: string;
8+
9+
constructor(message: string, error_code: number | string, status: number) {
10+
super(message);
11+
this.name = 'APIError';
12+
this.error_code = error_code;
13+
this.status = status;
14+
this.error_message = message;
15+
16+
// Remove the stack trace completely to avoid showing internal error handling
17+
this.stack = undefined;
18+
}
19+
20+
/**
21+
* Creates an APIError from an Axios error response
22+
* @param err - The Axios error object
23+
* @returns Formatted APIError with meaningful information
24+
*/
25+
static fromAxiosError(err: any): APIError {
26+
if (err.response?.data) {
27+
return APIError.fromResponseData(err.response.data, err.response.status);
28+
} else if (err.message) {
29+
// For network errors or other non-HTTP errors
30+
return new APIError(err.message, err.code || 'NETWORK_ERROR', 0);
31+
} else {
32+
// Fallback for unknown errors
33+
return new APIError('Unknown error occurred', 'UNKNOWN_ERROR', 0);
34+
}
35+
}
36+
37+
/**
38+
* Creates an APIError from response data
39+
* @param responseData - The response data from the API
40+
* @param status - The HTTP status code
41+
* @returns Formatted APIError
42+
*/
43+
static fromResponseData(responseData: any, status: number): APIError {
44+
// Extract error message with fallback chain
45+
const errorMessage = APIError.extractErrorMessage(responseData);
46+
47+
// Extract error code with fallback chain
48+
const errorCode = APIError.extractErrorCode(responseData, status);
49+
50+
return new APIError(errorMessage, errorCode, status);
51+
}
52+
53+
/**
54+
* Extracts error message from response data with multiple fallback options
55+
*/
56+
private static extractErrorMessage(responseData: any): string {
57+
if (responseData.error_message) return responseData.error_message;
58+
if (responseData.message) return responseData.message;
59+
if (responseData.error) return responseData.error;
60+
if (typeof responseData === 'string') return responseData;
61+
return 'Request failed';
62+
}
63+
64+
/**
65+
* Extracts error code from response data with fallback to status
66+
*/
67+
private static extractErrorCode(responseData: any, status: number): number | string {
68+
if (responseData.error_code) return responseData.error_code;
69+
if (responseData.code) return responseData.code;
70+
return status;
71+
}
72+
}

src/lib/request.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,14 @@
11
import { AxiosInstance } from './types';
2+
import { serialize } from './param-serializer';
3+
import { APIError } from './api-error';
24

35
/**
46
* Handles array parameters properly with & separators
57
* React Native compatible implementation without URLSearchParams.set()
68
*/
79
function serializeParams(params: any): string {
810
if (!params) return '';
9-
10-
const parts: string[] = [];
11-
Object.keys(params).forEach(key => {
12-
const value = params[key];
13-
if (Array.isArray(value)) {
14-
value.forEach(item => {
15-
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(item)}`);
16-
});
17-
} else if (value !== null && value !== undefined) {
18-
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
19-
}
20-
});
21-
22-
return parts.join('&');
11+
return serialize(params);
2312
}
2413

2514
/**
@@ -48,6 +37,15 @@ async function makeRequest(instance: AxiosInstance, url: string, requestConfig:
4837
}
4938
}
5039

40+
/**
41+
* Handles and formats errors from Axios requests
42+
* @param err - The error object from Axios
43+
* @returns Formatted error object with meaningful information
44+
*/
45+
function handleRequestError(err: any): Error {
46+
return APIError.fromAxiosError(err);
47+
}
48+
5149
export async function getData(instance: AxiosInstance, url: string, data?: any) {
5250
try {
5351
if (instance.stackConfig && instance.stackConfig.live_preview) {
@@ -87,6 +85,6 @@ export async function getData(instance: AxiosInstance, url: string, data?: any)
8785
throw response;
8886
}
8987
} catch (err: any) {
90-
throw err;
88+
throw handleRequestError(err);
9189
}
9290
}

test/contentstack-core.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ describe('contentstackCore', () => {
152152
it('should call the onError function when an error occurs', async () => {
153153
const onError = jest.fn();
154154
const options = {
155+
defaultHostname: 'cdn.contentstack.io',
155156
onError,
156157
};
157158

0 commit comments

Comments
 (0)