From f23e92d212666fb156225dbf009a4c2a61469eaa Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Mon, 9 Jun 2025 16:27:55 +0530 Subject: [PATCH] SK-2119: fix type gaps for error handling --- src/vault/client/index.ts | 213 +++++++++++++++++++-------- src/vault/controller/detect/index.ts | 3 +- src/vault/types/index.ts | 46 +++++- 3 files changed, 195 insertions(+), 67 deletions(-) diff --git a/src/vault/client/index.ts b/src/vault/client/index.ts index 0fb9ef22..d10225dc 100644 --- a/src/vault/client/index.ts +++ b/src/vault/client/index.ts @@ -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 { @@ -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' @@ -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') || ''; @@ -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 ) { diff --git a/src/vault/controller/detect/index.ts b/src/vault/controller/detect/index.ts index b6fceed9..c7cc0cf2 100644 --- a/src/vault/controller/detect/index.ts +++ b/src/vault/controller/detect/index.ts @@ -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 { @@ -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)) }); diff --git a/src/vault/types/index.ts b/src/vault/types/index.ts index b99d3d39..751e3533 100644 --- a/src/vault/types/index.ts +++ b/src/vault/types/index.ts @@ -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[]; @@ -76,4 +77,47 @@ export interface ParsedInsertBatchResponse { export interface DetokenizeData { token: string; redactionType?: RedactionType; -} \ No newline at end of file +} + +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; \ No newline at end of file