"use client"; import React, { useState } from "react"; import { ChartDataSource, QueryResult, ApiResponse } from "../types"; import { Card } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Plus, X, Play, AlertCircle } from "lucide-react"; interface ApiConfigProps { dataSource: ChartDataSource; onChange: (updates: Partial) => void; onTestResult?: (result: QueryResult) => void; } /** * REST API 설정 컴포넌트 * - API 엔드포인트 설정 * - 헤더 및 쿼리 파라미터 추가 * - JSON Path 설정 */ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps) { const [testing, setTesting] = useState(false); const [testResult, setTestResult] = useState(null); const [testError, setTestError] = useState(null); // 헤더 추가 const addHeader = () => { const headers = dataSource.headers || {}; const newKey = `header_${Object.keys(headers).length + 1}`; onChange({ headers: { ...headers, [newKey]: "" } }); }; // 헤더 제거 const removeHeader = (key: string) => { const headers = { ...dataSource.headers }; delete headers[key]; onChange({ headers }); }; // 헤더 업데이트 const updateHeader = (oldKey: string, newKey: string, value: string) => { const headers = { ...dataSource.headers }; delete headers[oldKey]; headers[newKey] = value; onChange({ headers }); }; // 쿼리 파라미터 추가 const addQueryParam = () => { const queryParams = dataSource.queryParams || {}; const newKey = `param_${Object.keys(queryParams).length + 1}`; onChange({ queryParams: { ...queryParams, [newKey]: "" } }); }; // 쿼리 파라미터 제거 const removeQueryParam = (key: string) => { const queryParams = { ...dataSource.queryParams }; delete queryParams[key]; onChange({ queryParams }); }; // 쿼리 파라미터 업데이트 const updateQueryParam = (oldKey: string, newKey: string, value: string) => { const queryParams = { ...dataSource.queryParams }; delete queryParams[oldKey]; queryParams[newKey] = value; onChange({ queryParams }); }; // API 테스트 const testApi = async () => { if (!dataSource.endpoint) { setTestError("API URL을 입력하세요"); return; } setTesting(true); setTestError(null); setTestResult(null); try { // 쿼리 파라미터 구성 const params = new URLSearchParams(); if (dataSource.queryParams) { Object.entries(dataSource.queryParams).forEach(([key, value]) => { if (key && value) { params.append(key, value); } }); } const url = `http://localhost:8080/api/dashboards/fetch-api?${params.toString()}`; 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 || "", }), }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const result: ApiResponse = await response.json(); if (!result.success) { throw new Error(result.message || "API 호출에 실패했습니다"); } setTestResult(result.data); onTestResult?.(result.data); } catch (err) { const errorMessage = err instanceof Error ? err.message : "알 수 없는 오류가 발생했습니다"; setTestError(errorMessage); } finally { setTesting(false); } }; return (

2단계: REST API 설정

외부 API에서 데이터를 가져올 설정을 입력하세요

{/* API URL */}
onChange({ endpoint: e.target.value })} className="mt-2" />

GET 요청을 보낼 API 엔드포인트

{/* HTTP 메서드 (고정) */}
GET (고정)

데이터 조회는 GET 메서드만 지원합니다

{/* 쿼리 파라미터 */}
{dataSource.queryParams && Object.keys(dataSource.queryParams).length > 0 ? (
{Object.entries(dataSource.queryParams).map(([key, value]) => (
updateQueryParam(key, e.target.value, value)} className="flex-1" /> updateQueryParam(key, key, e.target.value)} className="flex-1" />
))}
) : (

추가된 파라미터가 없습니다

)}

예: category=electronics, limit=10

{/* 헤더 */}
{/* 빠른 헤더 템플릿 */}
{dataSource.headers && Object.keys(dataSource.headers).length > 0 ? (
{Object.entries(dataSource.headers).map(([key, value]) => (
updateHeader(key, e.target.value, value)} className="flex-1" /> updateHeader(key, key, e.target.value)} className="flex-1" type={key.toLowerCase().includes("auth") ? "password" : "text"} />
))}
) : (

추가된 헤더가 없습니다

)}
{/* JSON Path */} onChange({ jsonPath: e.target.value })} />

JSON 응답에서 데이터 배열의 경로 (예: data.results, items, response.data)
비워두면 전체 응답을 사용합니다

{/* 테스트 버튼 */}
{/* 테스트 오류 */} {testError && (
API 호출 실패
{testError}
)} {/* 테스트 결과 */} {testResult && (
✅ API 호출 성공
총 {testResult.rows.length}개의 데이터를 불러왔습니다
컬럼: {testResult.columns.join(", ")}
)}
); }