restapi 여러개 띄우는거 작업 가능하게 하는거 진행중

This commit is contained in:
leeheejin
2025-10-27 18:33:15 +09:00
parent 4f2cf6c0ff
commit 5b394473f4
23 changed files with 4283 additions and 106 deletions

View File

@@ -9,6 +9,15 @@ import { Plus, X, Play, AlertCircle } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ExternalDbConnectionAPI, ExternalApiConnection } from "@/lib/api/externalDbConnection";
// 개별 API 소스 인터페이스
interface ApiSource {
id: string;
endpoint: string;
headers: KeyValuePair[];
queryParams: KeyValuePair[];
jsonPath?: string;
}
interface ApiConfigProps {
dataSource: ChartDataSource;
onChange: (updates: Partial<ChartDataSource>) => void;
@@ -52,8 +61,15 @@ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps
console.log("불러온 커넥션:", connection);
// 커넥션 설정을 API 설정에 자동 적용
// base_url과 endpoint_path를 조합하여 전체 URL 생성
const fullEndpoint = connection.endpoint_path
? `${connection.base_url}${connection.endpoint_path}`
: connection.base_url;
console.log("전체 엔드포인트:", fullEndpoint);
const updates: Partial<ChartDataSource> = {
endpoint: connection.base_url,
endpoint: fullEndpoint,
};
const headers: KeyValuePair[] = [];
@@ -119,6 +135,8 @@ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps
}
}
updates.type = "api"; // ⭐ 중요: type을 api로 명시
updates.method = "GET"; // 기본 메서드
updates.headers = headers;
updates.queryParams = queryParams;
console.log("최종 업데이트:", updates);
@@ -201,6 +219,17 @@ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps
return;
}
// 타일맵 URL 감지 (이미지 파일이므로 테스트 불가)
const isTilemapUrl =
dataSource.endpoint.includes('{z}') &&
dataSource.endpoint.includes('{y}') &&
dataSource.endpoint.includes('{x}');
if (isTilemapUrl) {
setTestError("타일맵 URL은 테스트할 수 없습니다. 지도 위젯에서 직접 확인하세요.");
return;
}
setTesting(true);
setTestError(null);
setTestResult(null);
@@ -248,7 +277,36 @@ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps
throw new Error(apiResponse.message || "외부 API 호출 실패");
}
const apiData = apiResponse.data;
let apiData = apiResponse.data;
// 텍스트 응답인 경우 파싱
if (apiData && typeof apiData === "object" && "text" in apiData && typeof apiData.text === "string") {
const textData = apiData.text;
// CSV 형식 파싱 (기상청 API)
if (textData.includes("#START7777") || textData.includes(",")) {
const lines = textData.split("\n").filter((line) => line.trim() && !line.startsWith("#"));
const parsedRows = lines.map((line) => {
const values = line.split(",").map((v) => v.trim());
return {
reg_up: values[0] || "",
reg_up_ko: values[1] || "",
reg_id: values[2] || "",
reg_ko: values[3] || "",
tm_fc: values[4] || "",
tm_ef: values[5] || "",
wrn: values[6] || "",
lvl: values[7] || "",
cmd: values[8] || "",
ed_tm: values[9] || "",
};
});
apiData = parsedRows;
} else {
// 일반 텍스트는 그대로 반환
apiData = [{ text: textData }];
}
}
// JSON Path 처리
let data = apiData;
@@ -313,41 +371,47 @@ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps
return (
<div className="space-y-4">
{/* 외부 커넥션 선택 */}
{apiConnections.length > 0 && (
<div className="space-y-2">
<Label className="text-xs font-medium text-gray-700"> ()</Label>
<Select value={selectedConnectionId} onValueChange={handleConnectionSelect}>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="저장된 커넥션 선택" />
</SelectTrigger>
<SelectContent className="z-[9999]">
<SelectItem value="manual" className="text-xs">
</SelectItem>
{apiConnections.map((conn) => (
{/* 외부 커넥션 선택 - 항상 표시 */}
<div className="space-y-2">
<Label className="text-xs font-medium text-gray-700"> ()</Label>
<Select value={selectedConnectionId} onValueChange={handleConnectionSelect}>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="저장된 커넥션 선택" />
</SelectTrigger>
<SelectContent className="z-[9999]" position="popper" sideOffset={4}>
<SelectItem value="manual" className="text-xs">
</SelectItem>
{apiConnections.length > 0 ? (
apiConnections.map((conn) => (
<SelectItem key={conn.id} value={String(conn.id)} className="text-xs">
{conn.connection_name}
{conn.description && <span className="ml-1.5 text-[10px] text-gray-500">({conn.description})</span>}
</SelectItem>
))}
</SelectContent>
</Select>
<p className="text-[11px] text-gray-500"> REST API </p>
</div>
)}
))
) : (
<SelectItem value="no-connections" disabled className="text-xs text-gray-500">
</SelectItem>
)}
</SelectContent>
</Select>
<p className="text-[11px] text-gray-500"> REST API </p>
</div>
{/* API URL */}
<div className="space-y-1.5">
<Label className="text-xs font-medium text-gray-700">API URL *</Label>
<Input
type="url"
placeholder="https://api.example.com/data"
placeholder="https://api.example.com/data 또는 /api/typ01/url/wrn_now_data.php"
value={dataSource.endpoint || ""}
onChange={(e) => onChange({ endpoint: e.target.value })}
className="h-8 text-xs"
/>
<p className="text-[11px] text-gray-500">GET API </p>
<p className="text-[11px] text-gray-500">
URL base_url ( base_url )
</p>
</div>
{/* 쿼리 파라미터 */}