Error Handling
The SDK provides a unified error handling pattern across REST and GraphQL APIs. All errors are normalized to a consistent SdkError structure.
SdkError Structure
typescript
interface SdkError extends Error {
name: 'SdkError';
message: string; // Human-readable error message
statusCode?: number; // HTTP status code (REST only)
classification: ErrorClassification; // Error category
requestId?: string; // Request tracking ID
details?: ErrorDetails; // Structured error details
cause?: Error; // Original error (minimal)
}
type ErrorClassification =
| 'VALIDATION_ERROR' // 400, 422 - Invalid input
| 'AUTHENTICATION_ERROR' // 401 - Invalid credentials
| 'AUTHORIZATION_ERROR' // 403 - Insufficient permissions
| 'NOT_FOUND' // 404 - Resource not found
| 'RATE_LIMIT' // 429 - Too many requests
| 'NETWORK_ERROR' // No response from server
| 'SERVER_ERROR' // 500+ - Server issues
| 'GRAPHQL_ERROR' // GraphQL-specific errors
| 'UNKNOWN_ERROR'; // Unclassified errors
interface ErrorDetails {
errorCode?: string; // API error code (e.g., 'error.msg.client.id.invalid')
validationErrors?: Array<{ // Field-level errors
field: string;
message: string;
code?: string;
value?: unknown;
args?: unknown[];
}>;
path?: string[]; // GraphQL field path
graphqlCode?: string; // GraphQL extension code
}Basic Error Handling
typescript
import { isSdkError, SdkError } from '@mbanq/core-sdk-js';
try {
const result = await client.request(GetClient(123));
} catch (error) {
if (isSdkError(error)) {
console.log('Error:', error.message);
console.log('Classification:', error.classification);
console.log('Status:', error.statusCode);
console.log('Request ID:', error.requestId);
// Access structured details
if (error.details?.validationErrors) {
error.details.validationErrors.forEach(ve => {
console.log(`Field ${ve.field}: ${ve.message}`);
});
}
}
}Classification-Based Handling
typescript
try {
await client.request(CreatePayment(paymentData));
} catch (error) {
if (isSdkError(error)) {
switch (error.classification) {
case 'AUTHENTICATION_ERROR':
// Refresh token or re-authenticate
await client.connect(credentials);
break;
case 'AUTHORIZATION_ERROR':
// Check 2FA or permissions
console.log('Access denied:', error.message);
break;
case 'VALIDATION_ERROR':
// Show field errors to user
error.details?.validationErrors?.forEach(e => {
showFieldError(e.field, e.message);
});
break;
case 'NOT_FOUND':
// Resource doesn't exist
console.log('Resource not found');
break;
case 'NETWORK_ERROR':
// Retry or show offline message
console.log('Network issue, please retry');
break;
case 'SERVER_ERROR':
// Log and show generic error
console.error('Server error:', error.requestId);
break;
}
}
}REST Error Example
When a REST API returns an error like:
json
{
"developerMessage": "The requested resource is not available.",
"httpStatusCode": "404",
"defaultUserMessage": "The requested resource is not available.",
"userMessageGlobalisationCode": "error.msg.resource.not.found",
"errors": [{
"developerMessage": "Client with identifier 21994 does not exist",
"defaultUserMessage": "Client with identifier 21994 does not exist",
"userMessageGlobalisationCode": "error.msg.client.id.invalid",
"parameterName": "id",
"value": null,
"args": [{"value": 21994}]
}]
}The SDK transforms it to:
typescript
{
name: 'SdkError',
message: 'The requested resource is not available.',
statusCode: 404,
classification: 'NOT_FOUND',
details: {
errorCode: 'error.msg.resource.not.found',
validationErrors: [{
field: 'id',
message: 'Client with identifier 21994 does not exist',
code: 'error.msg.client.id.invalid',
value: null,
args: [21994]
}]
}
}GraphQL Error Example
GraphQL errors like 2FA/permission issues:
json
{
"message": "Access to type 'PaymentRecipientTypeFormats' is restricted",
"extensions": { "code": "RESTRICTED", "classification": "DataFetchingException" }
}Are transformed to:
typescript
{
name: 'SdkError',
message: "Access to type 'PaymentRecipientTypeFormats' is restricted",
classification: 'AUTHORIZATION_ERROR',
details: {
graphqlCode: 'RESTRICTED',
errorCode: 'RESTRICTED'
}
}Type Guards
typescript
import { isSdkError } from '@mbanq/core-sdk-js';
// Check if error is an SdkError
if (isSdkError(error)) {
// TypeScript knows error is SdkError
console.log(error.classification);
}Accessing Original Error
For debugging, the original error is available via the standard cause property:
typescript
if (isSdkError(error) && error.cause) {
console.log('Original error:', error.cause.message);
console.log('Axios code:', (error.cause as any).code);
}