외부 커넥션 관리 ~ 테스트
This commit is contained in:
@@ -1,15 +1,8 @@
|
||||
// 외부 DB 연결 API 클라이언트
|
||||
// 작성일: 2024-12-17
|
||||
// 작성일: 2024-12-19
|
||||
|
||||
// API 기본 설정
|
||||
const getApiBaseUrl = () => {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
return "http://localhost:8080/api";
|
||||
}
|
||||
return "/api";
|
||||
};
|
||||
import { apiClient } from "./client";
|
||||
|
||||
// 타입 정의
|
||||
export interface ExternalDbConnection {
|
||||
id?: number;
|
||||
connection_name: string;
|
||||
@@ -45,214 +38,205 @@ export interface ApiResponse<T> {
|
||||
success: boolean;
|
||||
data?: T;
|
||||
message?: string;
|
||||
error?: string;
|
||||
error?: {
|
||||
code?: string;
|
||||
details?: string;
|
||||
};
|
||||
}
|
||||
|
||||
// DB 타입 옵션
|
||||
export const DB_TYPE_OPTIONS = [
|
||||
{ value: "mysql", label: "MySQL" },
|
||||
{ value: "postgresql", label: "PostgreSQL" },
|
||||
{ value: "oracle", label: "Oracle" },
|
||||
{ value: "mssql", label: "SQL Server" },
|
||||
{ value: "sqlite", label: "SQLite" },
|
||||
];
|
||||
// 연결 테스트 관련 타입
|
||||
export interface ConnectionTestRequest {
|
||||
db_type: string;
|
||||
host: string;
|
||||
port: number;
|
||||
database_name: string;
|
||||
username: string;
|
||||
password: string;
|
||||
connection_timeout?: number;
|
||||
ssl_enabled?: string;
|
||||
}
|
||||
|
||||
// DB 타입별 기본 설정
|
||||
export const DB_TYPE_DEFAULTS = {
|
||||
mysql: { port: 3306, driver: "mysql2" },
|
||||
postgresql: { port: 5432, driver: "pg" },
|
||||
oracle: { port: 1521, driver: "oracledb" },
|
||||
mssql: { port: 1433, driver: "mssql" },
|
||||
sqlite: { port: 0, driver: "sqlite3" },
|
||||
};
|
||||
export interface ConnectionTestResult {
|
||||
success: boolean;
|
||||
message: string;
|
||||
details?: {
|
||||
response_time?: number;
|
||||
server_version?: string;
|
||||
database_size?: string;
|
||||
};
|
||||
error?: {
|
||||
code?: string;
|
||||
details?: string;
|
||||
};
|
||||
}
|
||||
|
||||
// 활성 상태 옵션
|
||||
export const ACTIVE_STATUS_OPTIONS = [
|
||||
{ value: "Y", label: "활성" },
|
||||
{ value: "N", label: "비활성" },
|
||||
{ value: "ALL", label: "전체" },
|
||||
];
|
||||
|
||||
// API 클라이언트 클래스
|
||||
export class ExternalDbConnectionAPI {
|
||||
private static getAuthHeaders() {
|
||||
const token = localStorage.getItem("authToken");
|
||||
return {
|
||||
"Content-Type": "application/json",
|
||||
...(token && { Authorization: `Bearer ${token}` }),
|
||||
};
|
||||
}
|
||||
|
||||
private static async handleResponse<T>(response: Response): Promise<ApiResponse<T>> {
|
||||
try {
|
||||
// 응답이 JSON인지 확인
|
||||
const contentType = response.headers.get("content-type");
|
||||
if (!contentType || !contentType.includes("application/json")) {
|
||||
throw new Error(`서버에서 JSON이 아닌 응답을 받았습니다: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
return {
|
||||
success: false,
|
||||
message: data.message || `HTTP ${response.status}: ${response.statusText}`,
|
||||
error: data.error,
|
||||
};
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("API 응답 처리 오류:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.",
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
};
|
||||
}
|
||||
}
|
||||
private static readonly BASE_PATH = "/external-db-connections";
|
||||
|
||||
/**
|
||||
* 외부 DB 연결 목록 조회
|
||||
*/
|
||||
static async getConnections(filter?: ExternalDbConnectionFilter): Promise<ApiResponse<ExternalDbConnection[]>> {
|
||||
static async getConnections(filter: ExternalDbConnectionFilter = {}): Promise<ExternalDbConnection[]> {
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (filter) {
|
||||
Object.entries(filter).forEach(([key, value]) => {
|
||||
if (value && value.trim()) {
|
||||
params.append(key, value.trim());
|
||||
}
|
||||
});
|
||||
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 || "연결 목록 조회에 실패했습니다.");
|
||||
}
|
||||
|
||||
const url = `${getApiBaseUrl()}/external-db-connections${params.toString() ? `?${params.toString()}` : ""}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: this.getAuthHeaders(),
|
||||
});
|
||||
|
||||
return this.handleResponse<ExternalDbConnection[]>(response);
|
||||
return response.data.data || [];
|
||||
} catch (error) {
|
||||
console.error("외부 DB 연결 목록 조회 오류:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: "네트워크 오류가 발생했습니다.",
|
||||
error: error instanceof Error ? error.message : "Network error",
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 외부 DB 연결 조회
|
||||
*/
|
||||
static async getConnectionById(id: number): Promise<ApiResponse<ExternalDbConnection>> {
|
||||
static async getConnectionById(id: number): Promise<ExternalDbConnection> {
|
||||
try {
|
||||
const response = await fetch(`${getApiBaseUrl()}/external-db-connections/${id}`, {
|
||||
method: "GET",
|
||||
headers: this.getAuthHeaders(),
|
||||
});
|
||||
const response = await apiClient.get<ApiResponse<ExternalDbConnection>>(`${this.BASE_PATH}/${id}`);
|
||||
|
||||
return this.handleResponse<ExternalDbConnection>(response);
|
||||
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);
|
||||
return {
|
||||
success: false,
|
||||
message: "네트워크 오류가 발생했습니다.",
|
||||
error: error instanceof Error ? error.message : "Network error",
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 새 외부 DB 연결 생성
|
||||
*/
|
||||
static async createConnection(data: ExternalDbConnection): Promise<ApiResponse<ExternalDbConnection>> {
|
||||
static async createConnection(data: ExternalDbConnection): Promise<ExternalDbConnection> {
|
||||
try {
|
||||
const response = await fetch(`${getApiBaseUrl()}/external-db-connections`, {
|
||||
method: "POST",
|
||||
headers: this.getAuthHeaders(),
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
const response = await apiClient.post<ApiResponse<ExternalDbConnection>>(this.BASE_PATH, data);
|
||||
|
||||
return this.handleResponse<ExternalDbConnection>(response);
|
||||
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);
|
||||
return {
|
||||
success: false,
|
||||
message: "네트워크 오류가 발생했습니다.",
|
||||
error: error instanceof Error ? error.message : "Network error",
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 외부 DB 연결 수정
|
||||
*/
|
||||
static async updateConnection(
|
||||
id: number,
|
||||
data: Partial<ExternalDbConnection>,
|
||||
): Promise<ApiResponse<ExternalDbConnection>> {
|
||||
static async updateConnection(id: number, data: ExternalDbConnection): Promise<ExternalDbConnection> {
|
||||
try {
|
||||
const response = await fetch(`${getApiBaseUrl()}/external-db-connections/${id}`, {
|
||||
method: "PUT",
|
||||
headers: this.getAuthHeaders(),
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
const response = await apiClient.put<ApiResponse<ExternalDbConnection>>(`${this.BASE_PATH}/${id}`, data);
|
||||
|
||||
return this.handleResponse<ExternalDbConnection>(response);
|
||||
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);
|
||||
return {
|
||||
success: false,
|
||||
message: "네트워크 오류가 발생했습니다.",
|
||||
error: error instanceof Error ? error.message : "Network error",
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 외부 DB 연결 삭제
|
||||
*/
|
||||
static async deleteConnection(id: number): Promise<ApiResponse<void>> {
|
||||
static async deleteConnection(id: number): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(`${getApiBaseUrl()}/external-db-connections/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: this.getAuthHeaders(),
|
||||
});
|
||||
const response = await apiClient.delete<ApiResponse<null>>(`${this.BASE_PATH}/${id}`);
|
||||
|
||||
return this.handleResponse<void>(response);
|
||||
if (!response.data.success) {
|
||||
throw new Error(response.data.message || "연결 삭제에 실패했습니다.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("외부 DB 연결 삭제 오류:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: "네트워크 오류가 발생했습니다.",
|
||||
error: error instanceof Error ? error.message : "Network error",
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 지원하는 DB 타입 목록 조회
|
||||
* 지원되는 DB 타입 목록 조회
|
||||
*/
|
||||
static async getSupportedTypes(): Promise<
|
||||
ApiResponse<{ types: typeof DB_TYPE_OPTIONS; defaults: typeof DB_TYPE_DEFAULTS }>
|
||||
> {
|
||||
static async getSupportedTypes(): Promise<Array<{ value: string; label: string }>> {
|
||||
try {
|
||||
const response = await fetch(`${getApiBaseUrl()}/external-db-connections/types/supported`, {
|
||||
method: "GET",
|
||||
headers: this.getAuthHeaders(),
|
||||
});
|
||||
const response = await apiClient.get<ApiResponse<{ types: Array<{ value: string; label: string }> }>>(
|
||||
`${this.BASE_PATH}/types/supported`,
|
||||
);
|
||||
|
||||
return this.handleResponse<{ types: typeof DB_TYPE_OPTIONS; defaults: typeof DB_TYPE_DEFAULTS }>(response);
|
||||
if (!response.data.success) {
|
||||
throw new Error(response.data.message || "지원 DB 타입 조회에 실패했습니다.");
|
||||
}
|
||||
|
||||
return response.data.data?.types || [];
|
||||
} catch (error) {
|
||||
console.error("지원 DB 타입 조회 오류:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 데이터베이스 연결 테스트
|
||||
*/
|
||||
static async testConnection(testData: ConnectionTestRequest): Promise<ConnectionTestResult> {
|
||||
try {
|
||||
const response = await apiClient.post<ApiResponse<ConnectionTestResult>>(`${this.BASE_PATH}/test`, testData);
|
||||
|
||||
if (!response.data.success) {
|
||||
// 백엔드에서 테스트 실패 시에도 200으로 응답하지만 data.success가 false
|
||||
return (
|
||||
response.data.data || {
|
||||
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: error instanceof Error ? error.message : "Network error",
|
||||
message: "연결 테스트 중 오류가 발생했습니다.",
|
||||
error: {
|
||||
code: "NETWORK_ERROR",
|
||||
details: error instanceof Error ? error.message : "알 수 없는 오류",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user