374 lines
11 KiB
TypeScript
374 lines
11 KiB
TypeScript
// 외부 DB 연결 API 클라이언트
|
|
// 작성일: 2024-12-19
|
|
|
|
import { apiClient } from "./client";
|
|
|
|
export interface ExternalDbConnection {
|
|
id?: number;
|
|
connection_name: string;
|
|
description?: string;
|
|
db_type: "mysql" | "postgresql" | "oracle" | "mssql" | "sqlite" | "mariadb";
|
|
host: string;
|
|
port: number;
|
|
database_name: string;
|
|
username: string;
|
|
password: string;
|
|
connection_timeout?: number;
|
|
query_timeout?: number;
|
|
max_connections?: number;
|
|
ssl_enabled?: string;
|
|
ssl_cert_path?: string;
|
|
connection_options?: Record<string, unknown>;
|
|
company_code: string;
|
|
is_active: string;
|
|
created_date?: Date;
|
|
created_by?: string;
|
|
updated_date?: Date;
|
|
updated_by?: string;
|
|
}
|
|
|
|
export type AuthType = "none" | "api-key" | "bearer" | "basic" | "oauth2";
|
|
|
|
export interface ExternalApiConnection {
|
|
id?: number;
|
|
connection_name: string;
|
|
description?: string;
|
|
base_url: string;
|
|
endpoint_path?: string;
|
|
default_headers: Record<string, string>;
|
|
auth_type: AuthType;
|
|
auth_config?: {
|
|
keyLocation?: "header" | "query";
|
|
keyName?: string;
|
|
keyValue?: string;
|
|
token?: string;
|
|
username?: string;
|
|
password?: string;
|
|
clientId?: string;
|
|
clientSecret?: string;
|
|
tokenUrl?: string;
|
|
accessToken?: string;
|
|
};
|
|
timeout?: number;
|
|
company_code: string;
|
|
is_active: string;
|
|
created_date?: Date;
|
|
created_by?: string;
|
|
updated_date?: Date;
|
|
updated_by?: string;
|
|
}
|
|
|
|
export interface ExternalDbConnectionFilter {
|
|
db_type?: string;
|
|
is_active?: string;
|
|
company_code?: string;
|
|
search?: string;
|
|
}
|
|
|
|
export interface ApiResponse<T> {
|
|
success: boolean;
|
|
data?: T;
|
|
message?: string;
|
|
error?: {
|
|
code?: string;
|
|
details?: string;
|
|
};
|
|
}
|
|
|
|
// 연결 테스트 관련 타입
|
|
export interface ConnectionTestRequest {
|
|
db_type: string;
|
|
host: string;
|
|
port: number;
|
|
database_name: string;
|
|
username: string;
|
|
password: string;
|
|
connection_timeout?: number;
|
|
ssl_enabled?: string;
|
|
}
|
|
|
|
export interface ConnectionTestResult {
|
|
success: boolean;
|
|
message: string;
|
|
details?: {
|
|
response_time?: number;
|
|
server_version?: string;
|
|
database_size?: string;
|
|
};
|
|
error?: {
|
|
code?: string;
|
|
details?: string;
|
|
};
|
|
}
|
|
|
|
export class ExternalDbConnectionAPI {
|
|
private static readonly BASE_PATH = "/external-db-connections";
|
|
|
|
/**
|
|
* 외부 DB 연결 목록 조회
|
|
*/
|
|
static async getConnections(filter: ExternalDbConnectionFilter = {}): Promise<ExternalDbConnection[]> {
|
|
try {
|
|
const params = new URLSearchParams();
|
|
|
|
if (filter.db_type) params.append("db_type", filter.db_type);
|
|
if (filter.is_active) params.append("is_active", filter.is_active);
|
|
if (filter.company_code) params.append("company_code", filter.company_code);
|
|
if (filter.search) params.append("search", filter.search);
|
|
|
|
const response = await apiClient.get<ApiResponse<ExternalDbConnection[]>>(
|
|
`${this.BASE_PATH}?${params.toString()}`,
|
|
);
|
|
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.message || "연결 목록 조회에 실패했습니다.");
|
|
}
|
|
|
|
return response.data.data || [];
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 목록 조회 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 특정 외부 DB 연결 조회
|
|
*/
|
|
static async getConnectionById(id: number): Promise<ExternalDbConnection> {
|
|
try {
|
|
const response = await apiClient.get<ApiResponse<ExternalDbConnection>>(`${this.BASE_PATH}/${id}`);
|
|
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.message || "연결 정보 조회에 실패했습니다.");
|
|
}
|
|
|
|
if (!response.data.data) {
|
|
throw new Error("연결 정보를 찾을 수 없습니다.");
|
|
}
|
|
|
|
return response.data.data;
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 조회 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 새 외부 DB 연결 생성
|
|
*/
|
|
static async createConnection(data: ExternalDbConnection): Promise<ExternalDbConnection> {
|
|
try {
|
|
const response = await apiClient.post<ApiResponse<ExternalDbConnection>>(this.BASE_PATH, data);
|
|
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.message || "연결 생성에 실패했습니다.");
|
|
}
|
|
|
|
if (!response.data.data) {
|
|
throw new Error("생성된 연결 정보를 받을 수 없습니다.");
|
|
}
|
|
|
|
return response.data.data;
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 생성 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 외부 DB 연결 수정
|
|
*/
|
|
static async updateConnection(id: number, data: ExternalDbConnection): Promise<ExternalDbConnection> {
|
|
try {
|
|
const response = await apiClient.put<ApiResponse<ExternalDbConnection>>(`${this.BASE_PATH}/${id}`, data);
|
|
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.message || "연결 수정에 실패했습니다.");
|
|
}
|
|
|
|
if (!response.data.data) {
|
|
throw new Error("수정된 연결 정보를 받을 수 없습니다.");
|
|
}
|
|
|
|
return response.data.data;
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 수정 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 외부 DB 연결 삭제
|
|
*/
|
|
static async deleteConnection(id: number): Promise<void> {
|
|
try {
|
|
const response = await apiClient.delete<ApiResponse<null>>(`${this.BASE_PATH}/${id}`);
|
|
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.message || "연결 삭제에 실패했습니다.");
|
|
}
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 삭제 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 지원되는 DB 타입 목록 조회
|
|
*/
|
|
static async getSupportedTypes(): Promise<Array<{ value: string; label: string }>> {
|
|
try {
|
|
const response = await apiClient.get<ApiResponse<{ types: Array<{ value: string; label: string }> }>>(
|
|
`${this.BASE_PATH}/types/supported`,
|
|
);
|
|
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.message || "지원 DB 타입 조회에 실패했습니다.");
|
|
}
|
|
|
|
return response.data.data?.types || [];
|
|
} catch (error) {
|
|
console.error("지원 DB 타입 조회 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 데이터베이스 연결 테스트 (ID 기반)
|
|
*/
|
|
static async testConnection(connectionId: number, password?: string): Promise<ConnectionTestResult> {
|
|
try {
|
|
const response = await apiClient.post<ApiResponse<ConnectionTestResult>>(
|
|
`${this.BASE_PATH}/${connectionId}/test`,
|
|
password ? { password } : undefined,
|
|
);
|
|
|
|
if (!response.data.success) {
|
|
return {
|
|
success: false,
|
|
message: response.data.message || "연결 테스트에 실패했습니다.",
|
|
error: response.data.error,
|
|
};
|
|
}
|
|
|
|
return (
|
|
response.data.data || {
|
|
success: true,
|
|
message: response.data.message || "연결 테스트가 완료되었습니다.",
|
|
}
|
|
);
|
|
} catch (error) {
|
|
console.error("연결 테스트 오류:", error);
|
|
|
|
return {
|
|
success: false,
|
|
message: "연결 테스트 중 오류가 발생했습니다.",
|
|
error: {
|
|
code: "NETWORK_ERROR",
|
|
details: error instanceof Error ? error.message : "알 수 없는 오류",
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SQL 쿼리 실행
|
|
*/
|
|
/**
|
|
* 데이터베이스 테이블 목록 조회
|
|
*/
|
|
static async getTables(connectionId: number): Promise<ApiResponse<string[]>> {
|
|
try {
|
|
const response = await apiClient.get<ApiResponse<string[]>>(`${this.BASE_PATH}/${connectionId}/tables`);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error("테이블 목록 조회 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
static async getTableColumns(connectionId: number, tableName: string): Promise<ApiResponse<any[]>> {
|
|
try {
|
|
console.log("컬럼 정보 API 요청:", `${this.BASE_PATH}/${connectionId}/tables/${tableName}/columns`);
|
|
const response = await apiClient.get<ApiResponse<any[]>>(
|
|
`${this.BASE_PATH}/${connectionId}/tables/${tableName}/columns`,
|
|
);
|
|
console.log("컬럼 정보 API 응답:", response.data);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error("테이블 컬럼 조회 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
static async executeQuery(connectionId: number, query: string): Promise<ApiResponse<any[]>> {
|
|
try {
|
|
console.log("API 요청:", `${this.BASE_PATH}/${connectionId}/execute`, { query });
|
|
const response = await apiClient.post<ApiResponse<any[]>>(`${this.BASE_PATH}/${connectionId}/execute`, { query });
|
|
console.log("API 응답:", response.data);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error("SQL 쿼리 실행 오류:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 활성 제어 커넥션 목록 조회 (플로우 관리용)
|
|
*/
|
|
static async getActiveControlConnections(): Promise<ApiResponse<ExternalDbConnection[]>> {
|
|
try {
|
|
const response = await apiClient.get<ApiResponse<ExternalDbConnection[]>>(`${this.BASE_PATH}/control/active`);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error("활성 제어 커넥션 조회 오류:", error);
|
|
return {
|
|
success: false,
|
|
message: error instanceof Error ? error.message : "활성 제어 커넥션 조회에 실패했습니다.",
|
|
data: [],
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* REST API 연결 목록 조회 (외부 커넥션에서)
|
|
*/
|
|
static async getApiConnections(filter: { is_active?: string } = {}): Promise<ExternalApiConnection[]> {
|
|
try {
|
|
const params = new URLSearchParams();
|
|
if (filter.is_active) params.append("is_active", filter.is_active);
|
|
|
|
const response = await apiClient.get<ApiResponse<ExternalApiConnection[]>>(
|
|
`/external-rest-api-connections?${params.toString()}`,
|
|
);
|
|
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.message || "API 연결 목록 조회에 실패했습니다.");
|
|
}
|
|
|
|
return response.data.data || [];
|
|
} catch (error) {
|
|
console.error("API 연결 목록 조회 오류:", error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 특정 REST API 연결 조회
|
|
*/
|
|
static async getApiConnectionById(id: number): Promise<ExternalApiConnection | null> {
|
|
try {
|
|
const response = await apiClient.get<ApiResponse<ExternalApiConnection>>(`/external-rest-api-connections/${id}`);
|
|
|
|
if (!response.data.success || !response.data.data) {
|
|
return null;
|
|
}
|
|
|
|
return response.data.data;
|
|
} catch (error) {
|
|
console.error("API 연결 조회 오류:", error);
|
|
return null;
|
|
}
|
|
}
|
|
}
|