Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
213 changes: 148 additions & 65 deletions src/vault/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { AuthInfo, AuthType, LogLevel, MessageType, printLog, TYPES } from "../.
import { isExpired } from "../../utils/jwt-utils";
import logs from "../../utils/logs";
import Credentials from "../config/credentials";
import { SkyflowApiErrorLegacy, SkyflowApiErrorNewFormat, SkyflowErrorData } from "../types";

class VaultClient {

Expand Down Expand Up @@ -127,12 +128,12 @@ class VaultClient {
this.skyflowCredentials = credentials;
}

private normalizeErrorMeta(err: any) {
const isNewFormat = !!err?.rawResponse;
private normalizeErrorMeta(err: SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy | SkyflowError | Error) {
const isNewFormat = (err as SkyflowApiErrorNewFormat).rawResponse !== undefined;
if (isNewFormat) {
const headers = err?.rawResponse?.headers;
const headers = (err as SkyflowApiErrorNewFormat).rawResponse?.headers;
const contentType = headers?.get('content-type');
const requestId = headers?.get('x-request-id');
const requestId = headers?.get('x-request-id') || '';
const errorFromClientHeader = headers?.get('error-from-client');
const errorFromClient = errorFromClientHeader
? String(errorFromClientHeader).toLowerCase() === 'true'
Expand All @@ -145,9 +146,9 @@ class VaultClient {
errorFromClient
};
} else {
const headers = err?.headers || {};
const headers = (err as SkyflowApiErrorLegacy).headers || {};
const contentType = headers.get('content-type');
const requestId = headers.get('x-request-id');
const requestId = headers.get('x-request-id') || '';



Expand All @@ -166,104 +167,186 @@ class VaultClient {
}


failureResponse = (err: any) => new Promise((_, reject) => {
failureResponse = (err: SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy | SkyflowError | Error) => new Promise((_, reject) => {
const { isNewFormat, contentType, requestId, errorFromClient } = this.normalizeErrorMeta(err);

const data = isNewFormat ? err?.body?.error : err;
const data: SkyflowErrorData = isNewFormat
? (err as SkyflowApiErrorNewFormat).body?.error
: (err as SkyflowApiErrorLegacy).body?.error;

if (contentType) {
if (contentType.includes('application/json')) {
this.handleJsonError(err, data, requestId, reject, errorFromClient);
this.handleJsonError(err as SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy, data, requestId, reject, errorFromClient);
} else if (contentType.includes('text/plain')) {
this.handleTextError(err, data, requestId, reject, errorFromClient);
this.handleTextError(err as SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy, data, requestId, reject, errorFromClient);
} else {
this.handleGenericError(err, requestId, reject, errorFromClient);
this.handleGenericError(err as SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy, requestId, reject, errorFromClient);
}
} else {
this.handleGenericError(err, requestId, reject, errorFromClient);
this.handleGenericError(err as SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy, requestId, reject, errorFromClient);
}
});


private handleJsonError(err: any, data: any, requestId: string, reject: Function, errorFromClient?: boolean) {
const isNewFormat = !!err?.rawResponse;


private isSkyflowApiErrorNewFormat(err: SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy): err is SkyflowApiErrorNewFormat {
return (err as SkyflowApiErrorNewFormat).rawResponse !== undefined;
}

private handleJsonError(
err: SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy,
data: SkyflowErrorData,
requestId: string,
reject: Function,
errorFromClient?: boolean
) {
const isNewFormat = this.isSkyflowApiErrorNewFormat(err);

if (isNewFormat) {
let description = data?.message;
const grpcCode = data?.grpc_code;
const status = data?.http_status;
let details = data?.details || [];

const errorData = data as SkyflowApiErrorNewFormat['body']['error'];
let description: string = errorData?.message;
const grpcCode: number | string | undefined = errorData?.grpc_code;
const status: number | undefined = errorData?.http_code;
let details: any = errorData?.details || [];

if (errorFromClient !== undefined) {
details = Array.isArray(details)
? [...details, { errorFromClient }]
: [{ errorFromClient }];
details = Array.isArray(details)
? [...details, { errorFromClient }]
: [{ errorFromClient }];
}

this.logAndRejectError(description, err, requestId, reject, status, grpcCode, details, isNewFormat);

this.logAndRejectError(
description,
err,
requestId,
reject,
status,
grpcCode,
details,
isNewFormat
);
} else {
let description = data;
const statusCode = description?.statusCode;
const grpcCode = description?.grpcCode;
let details = description?.error?.details;

// data is SkyflowApiErrorLegacyBody['error']
const legacyErr = err as SkyflowApiErrorLegacy;
const errorData = legacyErr.body?.error;
let description: string = errorData?.message || errorMessages.ERROR_OCCURRED;
const statusCode: number | undefined = errorData?.http_code;
const grpcCode: number | string | undefined = errorData?.grpc_code;
let details: any = errorData?.details || [];

if (errorFromClient !== undefined) {
details = Array.isArray(details)
? [...details, { errorFromClient }]
: [{ errorFromClient }];
details = Array.isArray(details)
? [...details, { errorFromClient }]
: [{ errorFromClient }];
}

description = description?.body?.error?.message || description;
this.logAndRejectError(description, err, requestId, reject, statusCode, grpcCode, details, isNewFormat);

this.logAndRejectError(
description,
err,
requestId,
reject,
statusCode,
grpcCode,
details,
isNewFormat
);
}
}


private handleTextError(err: any, data: any, requestId: string, reject: Function, errorFromClient?: boolean) {
const isNewFormat = !!err?.rawResponse

private handleTextError(
err: SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy,
data: SkyflowErrorData,
requestId: string,
reject: Function,
errorFromClient?: boolean
) {
const isNewFormat = this.isSkyflowApiErrorNewFormat(err);
let details: any = [];

if (errorFromClient !== undefined) {
details.push({ errorFromClient });
}

const description = isNewFormat ? data?.message: data?.body?.error?.message;
const status = isNewFormat ? data?.http_status : err?.body?.error?.http_status;
const grpcCode = isNewFormat ? data?.grpc_code : err?.body?.error?.grpc_code;
this.logAndRejectError(description, err, requestId, reject, status, grpcCode, details, isNewFormat);

let description: string;
let status: number | undefined;
let grpcCode: number | string | undefined;

if (isNewFormat) {
const errorData = data as SkyflowApiErrorNewFormat['body']['error'];
description = errorData?.message || errorMessages.ERROR_OCCURRED;
status = errorData?.http_code;
grpcCode = errorData?.grpc_code;
} else {
const legacyErr = err as SkyflowApiErrorLegacy;
const errorData = legacyErr.body?.error;
description = errorData?.message || errorMessages.ERROR_OCCURRED;
status = errorData?.http_code;
grpcCode = errorData?.grpc_code;
}

this.logAndRejectError(
description,
err,
requestId,
reject,
status,
grpcCode,
details,
isNewFormat
);
}


private handleGenericError(err: any, requestId: string, reject: Function, errorFromClient?: boolean) {
const isNewFormat = !!err?.rawResponse;
let description: any;
let grpcCode: any;

private handleGenericError(
err: SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy,
requestId: string,
reject: Function,
errorFromClient?: boolean
) {
const isNewFormat = this.isSkyflowApiErrorNewFormat(err);
let description: string;
let grpcCode: number | string | undefined;
let details: any = [];

if (isNewFormat) {
description = err?.body?.error?.message || errorMessages.GENERIC_API_ERROR || err?.message
grpcCode = err?.body?.error?.grpc_code;
details = err?.body?.error?.details || [];
const errorData = (err as SkyflowApiErrorNewFormat).body?.error;
description =
errorData?.message ??
(err as SkyflowApiErrorNewFormat).message ??
errorMessages.GENERIC_API_ERROR;
grpcCode = errorData?.grpc_code;
details = errorData?.details || [];
} else {
description = err?.body?.error?.message || errorMessages.ERROR_OCCURRED;
const legacyErr = err as SkyflowApiErrorLegacy;
const errorData = legacyErr.body?.error;
description = errorData?.message || errorMessages.ERROR_OCCURRED;
grpcCode = errorData?.grpc_code;
details = errorData?.details || [];
}

if (errorFromClient !== undefined) {
details = Array.isArray(details)
? [...details, { errorFromClient }]
: [{ errorFromClient }];
? [...details, { errorFromClient }]
: [{ errorFromClient }];
}

this.logAndRejectError(description, err, requestId, reject, undefined, grpcCode, details, isNewFormat);

this.logAndRejectError(
description,
err,
requestId,
reject,
undefined,
grpcCode,
details,
isNewFormat
);
}

private logAndRejectError(
description: string,
err: any,
err: SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy,
requestId: string,
reject: Function,
httpStatus?: number,
grpcCode?: number,
grpcCode?: number | string,
details?: any,
isNewError?: boolean
) {
Expand Down
3 changes: 2 additions & 1 deletion src/vault/controller/detect/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import SkyflowError from "../../../error";
import SKYFLOW_ERROR_CODE from "../../../error/codes";
import GetDetectRunRequest from "../../model/request/get-detect-run";
import Transformations from "../../model/options/deidentify-text/transformations";
import { SkyflowAllError } from "../../types";

class DetectController {

Expand Down Expand Up @@ -396,7 +397,7 @@ class DetectController {
break;

}
}).catch((error: any) => {
}).catch((error: SkyflowAllError) => {
printLog(logs.errorLogs[`${requestType}_REQUEST_REJECTED`], MessageType.ERROR, this.client.getLogLevel());
this.client.failureResponse(error).catch((err) => reject(err))
});
Expand Down
46 changes: 45 additions & 1 deletion src/vault/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import VaultController from "../controller/vault";
import ConnectionController from "../controller/connections";
import VaultClient from "../client";
import DetectController from "../controller/detect";
import SkyflowError from "../../error";

export interface SkyflowConfig {
vaultConfigs?: VaultConfig[];
Expand Down Expand Up @@ -76,4 +77,47 @@ export interface ParsedInsertBatchResponse {
export interface DetokenizeData {
token: string;
redactionType?: RedactionType;
}
}

export interface SkyflowApiErrorNewFormat {
rawResponse: {
headers: { get(key: string): string | undefined };
};
body: {
error: {
message: string;
http_code?: number;
grpc_code?: number | string;
details?: any[];
};
};
statusCode?: number;
message?: string;
}

export interface SkyflowApiErrorLegacyBody {
error: {
message: string;
http_code?: number;
grpc_code?: number | string;
details?: any[];
};
}

export interface SkyflowApiErrorLegacy {
headers: { get(key: string): string | undefined };
body?: SkyflowApiErrorLegacyBody;
statusCode?: number;
message?: string;
}

export type SkyflowAllError =
| SkyflowApiErrorNewFormat
| SkyflowApiErrorLegacy
| SkyflowError
| Error;

export type SkyflowErrorData =
| SkyflowApiErrorNewFormat['body']['error']
| SkyflowApiErrorLegacyBody['error']
| undefined;
Loading