Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f565608
fixing the error message format in integration test
anujachakraborty Apr 2, 2025
6ef308b
modified the error message format for all methods
anujachakraborty Apr 7, 2025
aead58b
modified the error handling logic and its corresponsding test cases
anujachakraborty Apr 9, 2025
3fbcedf
Bump typescript-eslint from 8.27.0 to 8.28.0 (#114)
dependabot[bot] Apr 1, 2025
6f75fea
Bump rollup from 4.37.0 to 4.38.0 (#117)
dependabot[bot] Apr 1, 2025
cb545cc
Bump typescript-eslint from 8.28.0 to 8.29.0 (#119)
dependabot[bot] Apr 1, 2025
0242a52
Bump ts-jest from 29.2.6 to 29.3.1 (#118)
dependabot[bot] Apr 1, 2025
2b6e9f0
Bump rollup from 4.38.0 to 4.39.0 (#122)
dependabot[bot] Apr 4, 2025
1ce55db
Bump eslint-plugin-prettier from 5.2.5 to 5.2.6 (#125)
dependabot[bot] Apr 4, 2025
3ca9327
Bump @types/node from 22.13.14 to 22.14.0 (#126)
dependabot[bot] Apr 4, 2025
38007a4
Bump typedoc from 0.28.1 to 0.28.2 (#127)
dependabot[bot] Apr 7, 2025
7ca2355
Bump typescript from 5.8.2 to 5.8.3 (#128)
dependabot[bot] Apr 7, 2025
3752e06
Bump eslint from 9.23.0 to 9.24.0 (#129)
dependabot[bot] Apr 7, 2025
6739085
Bump @typescript-eslint/parser from 8.29.0 to 8.29.1 (#132)
dependabot[bot] Apr 8, 2025
dcaad6e
Bump typescript-eslint from 8.29.0 to 8.29.1 (#130)
dependabot[bot] Apr 8, 2025
c4715ab
Bump eslint-config-prettier from 10.1.1 to 10.1.2 (#133)
dependabot[bot] Apr 11, 2025
3c198f1
Bump rollup from 4.39.0 to 4.40.0 (#134)
dependabot[bot] Apr 14, 2025
a478d70
Bump @types/node from 22.14.0 to 22.14.1 (#135)
dependabot[bot] Apr 14, 2025
27e4e0a
Bump ts-jest from 29.3.1 to 29.3.2 (#136)
dependabot[bot] Apr 14, 2025
a59881d
provided the final fix for error handling
anujachakraborty Apr 15, 2025
4a1a057
Merge remote-tracking branch 'origin/main' into my-features
aaronzi Apr 15, 2025
ddd443b
Adds missing tests
aaronzi Apr 15, 2025
0fc3803
Improves error handling to account for different error types
aaronzi Apr 15, 2025
2405ac7
Finalizes error handling
aaronzi Apr 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 41 additions & 27 deletions src/clients/AasRepositoryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
AssetAdministrationShellRepositoryAPIApi as AasRepository,
Configuration,
PagedResultPagingMetadata,
RequiredError,
Result,
} from '../generated';
import { applyDefaults } from '../lib/apiConfig';
import { base64Encode } from '../lib/base64Url';
Expand All @@ -21,6 +21,7 @@ import {
convertCoreAssetInformationToApiAssetInformation,
convertCoreReferenceToApiReference,
} from '../lib/convertAasTypes';
import { handleApiError } from '../lib/errorHandler';

export class AasRepositoryClient {
/**
Expand All @@ -47,7 +48,7 @@ export class AasRepositoryClient {
pagedResult: PagedResultPagingMetadata | undefined;
result: AssetAdministrationShell[];
},
RequiredError
Result
>
> {
const { configuration, assetIds, idShort, limit, cursor } = options;
Expand All @@ -69,7 +70,8 @@ export class AasRepositoryClient {
data: { pagedResult: result.pagingMetadata, result: shells },
};
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -85,7 +87,7 @@ export class AasRepositoryClient {
async postAssetAdministrationShell(options: {
configuration: Configuration;
assetAdministrationShell: AssetAdministrationShell;
}): Promise<ApiResult<AssetAdministrationShell, RequiredError>> {
}): Promise<ApiResult<AssetAdministrationShell, Result>> {
const { configuration, assetAdministrationShell } = options;

try {
Expand All @@ -97,7 +99,8 @@ export class AasRepositoryClient {

return { success: true, data: convertApiAasToCoreAas(result) };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -113,7 +116,7 @@ export class AasRepositoryClient {
async deleteAssetAdministrationShellById(options: {
configuration: Configuration;
aasIdentifier: string;
}): Promise<ApiResult<void, RequiredError>> {
}): Promise<ApiResult<void, Result>> {
const { configuration, aasIdentifier } = options;

try {
Expand All @@ -127,7 +130,8 @@ export class AasRepositoryClient {

return { success: true, data: result };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -143,7 +147,7 @@ export class AasRepositoryClient {
async getAssetAdministrationShellById(options: {
configuration: Configuration;
aasIdentifier: string;
}): Promise<ApiResult<AssetAdministrationShell, RequiredError>> {
}): Promise<ApiResult<AssetAdministrationShell, Result>> {
const { configuration, aasIdentifier } = options;

try {
Expand All @@ -157,7 +161,8 @@ export class AasRepositoryClient {

return { success: true, data: convertApiAasToCoreAas(result) };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -175,7 +180,7 @@ export class AasRepositoryClient {
configuration: Configuration;
aasIdentifier: string;
assetAdministrationShell: AssetAdministrationShell;
}): Promise<ApiResult<void, RequiredError>> {
}): Promise<ApiResult<void, Result>> {
const { configuration, aasIdentifier, assetAdministrationShell } = options;

try {
Expand All @@ -190,7 +195,8 @@ export class AasRepositoryClient {

return { success: true, data: result };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -206,7 +212,7 @@ export class AasRepositoryClient {
async getAssetInformation(options: {
configuration: Configuration;
aasIdentifier: string;
}): Promise<ApiResult<AssetInformation, RequiredError>> {
}): Promise<ApiResult<AssetInformation, Result>> {
const { configuration, aasIdentifier } = options;

try {
Expand All @@ -223,7 +229,8 @@ export class AasRepositoryClient {
data: convertApiAssetInformationToCoreAssetInformation(result),
};
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -241,7 +248,7 @@ export class AasRepositoryClient {
configuration: Configuration;
aasIdentifier: string;
assetInformation: AssetInformation;
}): Promise<ApiResult<void, RequiredError>> {
}): Promise<ApiResult<void, Result>> {
const { configuration, aasIdentifier, assetInformation } = options;

try {
Expand All @@ -256,7 +263,8 @@ export class AasRepositoryClient {

return { success: true, data: result };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -272,7 +280,7 @@ export class AasRepositoryClient {
async deleteThumbnail(options: {
configuration: Configuration;
aasIdentifier: string;
}): Promise<ApiResult<void, RequiredError>> {
}): Promise<ApiResult<void, Result>> {
const { configuration, aasIdentifier } = options;
try {
const apiInstance = new AasRepository(applyDefaults(configuration));
Expand All @@ -285,7 +293,8 @@ export class AasRepositoryClient {

return { success: true, data: result };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -301,7 +310,7 @@ export class AasRepositoryClient {
async getThumbnail(options: {
configuration: Configuration;
aasIdentifier: string;
}): Promise<ApiResult<Blob, RequiredError>> {
}): Promise<ApiResult<Blob, Result>> {
const { configuration, aasIdentifier } = options;

try {
Expand All @@ -315,7 +324,8 @@ export class AasRepositoryClient {

return { success: true, data: result };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -335,7 +345,7 @@ export class AasRepositoryClient {
aasIdentifier: string;
fileName: string;
file: Blob;
}): Promise<ApiResult<void, RequiredError>> {
}): Promise<ApiResult<void, Result>> {
const { configuration, aasIdentifier, fileName, file } = options;

try {
Expand All @@ -351,7 +361,8 @@ export class AasRepositoryClient {

return { success: true, data: result };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -371,7 +382,7 @@ export class AasRepositoryClient {
aasIdentifier: string;
limit?: number;
cursor?: string;
}): Promise<ApiResult<{ pagedResult: PagedResultPagingMetadata | undefined; result: Reference[] }, RequiredError>> {
}): Promise<ApiResult<{ pagedResult: PagedResultPagingMetadata | undefined; result: Reference[] }, Result>> {
const { configuration, aasIdentifier, limit, cursor } = options;

try {
Expand All @@ -394,7 +405,8 @@ export class AasRepositoryClient {
},
};
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -412,7 +424,7 @@ export class AasRepositoryClient {
configuration: Configuration;
aasIdentifier: string;
submodelReference: Reference;
}): Promise<ApiResult<Reference, RequiredError>> {
}): Promise<ApiResult<Reference, Result>> {
const { configuration, aasIdentifier, submodelReference } = options;

try {
Expand All @@ -427,7 +439,8 @@ export class AasRepositoryClient {

return { success: true, data: convertApiReferenceToCoreReference(result) };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}

Expand All @@ -445,7 +458,7 @@ export class AasRepositoryClient {
configuration: Configuration;
aasIdentifier: string;
submodelIdentifier: string;
}): Promise<ApiResult<void, RequiredError>> {
}): Promise<ApiResult<void, Result>> {
const { configuration, aasIdentifier, submodelIdentifier } = options;

try {
Expand All @@ -461,7 +474,8 @@ export class AasRepositoryClient {

return { success: true, data: result };
} catch (err) {
return { success: false, error: err as RequiredError };
const customError = await handleApiError(err);
return { success: false, error: customError };
}
}
}
4 changes: 4 additions & 0 deletions src/lib/base64Url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* @returns {string} The Base64 encoded string, converted to URL-safe format if requested.
*/
export function base64Encode(string: string, urlSafe: boolean = true): string {
if (string === null || string === undefined) return '';

string = string.trim();

if (string === '') return '';
Expand Down Expand Up @@ -49,6 +51,8 @@ export function base64Encode(string: string, urlSafe: boolean = true): string {
* @returns {string} The decoded string.
*/
export function base64Decode(urlSafeBase64String: string): string {
if (urlSafeBase64String === null || urlSafeBase64String === undefined) return '';

urlSafeBase64String = urlSafeBase64String.trim();

if (urlSafeBase64String === '') return '';
Expand Down
99 changes: 99 additions & 0 deletions src/lib/errorHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { FetchError, Message, RequiredError, ResponseError, Result } from '../generated';

/**
* Processes errors from API calls and standardizes them to a Result object
* with a consistent messages array following the API spec guidelines.
*
* @param err The error thrown during an API call
* @returns A standardized Result object containing error messages
*/
export async function handleApiError(err: unknown): Promise<Result> {
try {
// Check if the error already has the expected format with messages array
const errorAny = err as any;

Check warning on line 13 in src/lib/errorHandler.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
if (errorAny?.messages && Array.isArray(errorAny.messages)) {
return { messages: errorAny.messages };
}

// Get current timestamp with millisecond precision as a string
const timestamp = (new Date().getTime() / 1000).toString();

let message: Message = {
code: '500',
messageType: 'Exception',
timestamp: timestamp,
text: 'Unknown error',
};

// Handle different error types
if (err instanceof RequiredError) {
message = {
code: '400',
messageType: 'Exception',
text: err.message || `Required parameter missing: ${err.field}`,
timestamp: timestamp,
};
} else if (err instanceof ResponseError) {
// Try to parse response body for messages
const responseBody = err.response;

try {
// Check if the response already contains a messages array
const responseData = responseBody && responseBody.json ? await responseBody.json() : null;

if (responseData?.messages && Array.isArray(responseData.messages)) {
return { messages: responseData.messages };
}

// Otherwise, create a message with the status code
message = {
code: err.response.status.toString(),
messageType: 'Exception',
text: err.message || `HTTP ${err.response.status} - Response returned an error code`,
timestamp: timestamp,
};
} catch {
// If we can't parse the body, create a basic message
message = {
code: err.response.status.toString(),
messageType: 'Exception',
text: `HTTP ${err.response.status} - Response returned an error code`,
timestamp: timestamp,
};
}
} else if (err instanceof FetchError) {
message = {
code: '0',
messageType: 'Exception',
text: err.message || 'Network request failed',
timestamp: timestamp,
};
} else if (err instanceof Error) {
message = {
code: '500',
messageType: 'Exception',
text: err.message || 'Unknown error occurred',
timestamp: timestamp,
};
}

return { messages: [message] };
} catch (handlerError) {
// If our error handler throws an error, capture that and return a fallback error
console.error('Error in error handler:', handlerError);

// Get current timestamp with millisecond precision as a string for the fallback error
const timestamp = (new Date().getTime() / 1000).toString();

return {
messages: [
{
code: '500',
messageType: 'Exception',
text: 'An error occurred while processing another error',
timestamp: timestamp,
},
],
};
}
}
Loading