api 호출 오류 수정

This commit is contained in:
dohyeons 2025-10-14 17:54:28 +09:00
parent bed23e256b
commit 2e84c4272f
2 changed files with 124 additions and 38 deletions

View File

@ -36,40 +36,100 @@ export function ChartRenderer({ element, data, width = 250, height = 200 }: Char
}
// 데이터 소스가 설정되어 있으면 페칭
if (element.dataSource && element.dataSource.query && element.chartConfig) {
if (element.dataSource && element.chartConfig) {
setIsLoading(true);
setError(null);
try {
let queryResult: QueryResult;
// 현재 DB vs 외부 DB 분기
if (element.dataSource.connectionType === "external" && element.dataSource.externalConnectionId) {
// 외부 DB
const result = await ExternalDbConnectionAPI.executeQuery(
parseInt(element.dataSource.externalConnectionId),
element.dataSource.query,
);
if (!result.success) {
throw new Error(result.message || "외부 DB 쿼리 실행 실패");
// REST API vs Database 분기
if (element.dataSource.type === "api" && element.dataSource.endpoint) {
// REST API
const params = new URLSearchParams();
if (element.dataSource.queryParams) {
Object.entries(element.dataSource.queryParams).forEach(([key, value]) => {
if (key && value) {
params.append(key, value);
}
});
}
let url = element.dataSource.endpoint;
const queryString = params.toString();
if (queryString) {
url += (url.includes("?") ? "&" : "?") + queryString;
}
const headers: Record<string, string> = {
"Content-Type": "application/json",
...element.dataSource.headers,
};
const response = await fetch(url, {
method: "GET",
headers,
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const apiData = await response.json();
// JSON Path 처리
let processedData = apiData;
if (element.dataSource.jsonPath) {
const paths = element.dataSource.jsonPath.split(".");
for (const path of paths) {
if (processedData && typeof processedData === "object" && path in processedData) {
processedData = processedData[path];
} else {
throw new Error(`JSON Path "${element.dataSource.jsonPath}"에서 데이터를 찾을 수 없습니다`);
}
}
}
const rows = Array.isArray(processedData) ? processedData : [processedData];
const columns = rows.length > 0 ? Object.keys(rows[0]) : [];
queryResult = {
columns: result.data?.[0] ? Object.keys(result.data[0]) : [],
rows: result.data || [],
totalRows: result.data?.length || 0,
columns,
rows,
totalRows: rows.length,
executionTime: 0,
};
} else if (element.dataSource.query) {
// Database (현재 DB 또는 외부 DB)
if (element.dataSource.connectionType === "external" && element.dataSource.externalConnectionId) {
// 외부 DB
const result = await ExternalDbConnectionAPI.executeQuery(
parseInt(element.dataSource.externalConnectionId),
element.dataSource.query,
);
if (!result.success) {
throw new Error(result.message || "외부 DB 쿼리 실행 실패");
}
queryResult = {
columns: result.data?.[0] ? Object.keys(result.data[0]) : [],
rows: result.data || [],
totalRows: result.data?.length || 0,
executionTime: 0,
};
} else {
// 현재 DB
const result = await dashboardApi.executeQuery(element.dataSource.query);
queryResult = {
columns: result.columns,
rows: result.rows,
totalRows: result.rowCount,
executionTime: 0,
};
}
} else {
// 현재 DB
const result = await dashboardApi.executeQuery(element.dataSource.query);
queryResult = {
columns: result.columns,
rows: result.rows,
totalRows: result.rowCount,
executionTime: 0,
};
throw new Error("데이터 소스가 올바르게 설정되지 않았습니다");
}
// ChartData로 변환

View File

@ -91,33 +91,59 @@ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps
});
}
const url = `http://localhost:8080/api/dashboards/fetch-api?${params.toString()}`;
// URL 구성
let url = dataSource.endpoint;
const queryString = params.toString();
if (queryString) {
url += (url.includes("?") ? "&" : "?") + queryString;
}
// 헤더 구성
const headers: Record<string, string> = {
"Content-Type": "application/json",
...dataSource.headers,
};
// 외부 API 직접 호출
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token") || "test-token"}`,
},
body: JSON.stringify({
endpoint: dataSource.endpoint,
headers: dataSource.headers || {},
jsonPath: dataSource.jsonPath || "",
}),
method: "GET",
headers,
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const result: ApiResponse<QueryResult> = await response.json();
const apiData = await response.json();
if (!result.success) {
throw new Error(result.message || "API 호출에 실패했습니다");
// JSON Path 처리
let data = apiData;
if (dataSource.jsonPath) {
const paths = dataSource.jsonPath.split(".");
for (const path of paths) {
if (data && typeof data === "object" && path in data) {
data = data[path];
} else {
throw new Error(`JSON Path "${dataSource.jsonPath}"에서 데이터를 찾을 수 없습니다`);
}
}
}
setTestResult(result.data);
onTestResult?.(result.data);
// 배열이 아니면 배열로 변환
const rows = Array.isArray(data) ? data : [data];
// 컬럼 추출
const columns = rows.length > 0 ? Object.keys(rows[0]) : [];
const result: QueryResult = {
columns,
rows,
totalRows: rows.length,
executionTime: 0,
};
setTestResult(result);
onTestResult?.(result);
} catch (err) {
const errorMessage = err instanceof Error ? err.message : "알 수 없는 오류가 발생했습니다";
setTestError(errorMessage);