--- alwaysApply: true description: API 요청 시 항상 전용 API 클라이언트를 사용하도록 강제하는 규칙 --- # API 클라이언트 사용 규칙 ## 핵심 원칙 **절대 `fetch`를 직접 사용하지 않고, 반드시 전용 API 클라이언트를 사용해야 합니다.** ## 이유 1. **환경별 URL 자동 처리**: 프로덕션(`v1.vexplor.com`)과 개발(`localhost`) 환경에서 올바른 백엔드 서버로 요청 2. **일관된 에러 처리**: 모든 API 호출에서 동일한 에러 핸들링 3. **인증 토큰 자동 포함**: Authorization 헤더 자동 추가 4. **유지보수성**: API 변경 시 한 곳에서만 수정 ## API 클라이언트 위치 ``` frontend/lib/api/ ├── client.ts # Axios 기반 공통 클라이언트 ├── flow.ts # 플로우 관리 API ├── dashboard.ts # 대시보드 API ├── mail.ts # 메일 API ├── externalCall.ts # 외부 호출 API ├── company.ts # 회사 관리 API └── file.ts # 파일 업로드/다운로드 API ``` ## 올바른 사용법 ### ❌ 잘못된 방법 (절대 사용 금지) ```typescript // 직접 fetch 사용 - 환경별 URL이 자동 처리되지 않음 const response = await fetch("/api/flow/definitions/29/steps"); const data = await response.json(); // 상대 경로 - 프로덕션에서 잘못된 도메인으로 요청 const response = await fetch(`/api/flow/${flowId}/steps`); ``` ### ✅ 올바른 방법 ```typescript // 1. API 클라이언트 함수 import import { getFlowSteps } from "@/lib/api/flow"; // 2. 함수 호출 const stepsResponse = await getFlowSteps(flowId); if (stepsResponse.success && stepsResponse.data) { setSteps(stepsResponse.data); } ``` ## 주요 API 클라이언트 함수 ### 플로우 관리 ([flow.ts](mdc:frontend/lib/api/flow.ts)) ```typescript import { getFlowDefinitions, // 플로우 목록 getFlowById, // 플로우 상세 createFlowDefinition, // 플로우 생성 updateFlowDefinition, // 플로우 수정 deleteFlowDefinition, // 플로우 삭제 getFlowSteps, // 스텝 목록 ⭐ createFlowStep, // 스텝 생성 updateFlowStep, // 스텝 수정 deleteFlowStep, // 스텝 삭제 getFlowConnections, // 연결 목록 ⭐ createFlowConnection, // 연결 생성 deleteFlowConnection, // 연결 삭제 getStepDataCount, // 스텝 데이터 카운트 getStepDataList, // 스텝 데이터 목록 getAllStepCounts, // 모든 스텝 카운트 moveData, // 데이터 이동 moveBatchData, // 배치 데이터 이동 getAuditLogs, // 오딧 로그 } from "@/lib/api/flow"; ``` ### Axios 클라이언트 ([client.ts](mdc:frontend/lib/api/client.ts)) ```typescript import apiClient from "@/lib/api/client"; // GET 요청 const response = await apiClient.get("/api/endpoint"); // POST 요청 const response = await apiClient.post("/api/endpoint", { data }); // PUT 요청 const response = await apiClient.put("/api/endpoint", { data }); // DELETE 요청 const response = await apiClient.delete("/api/endpoint"); ``` ## 새로운 API 함수 추가 가이드 기존 API 클라이언트에 함수가 없는 경우: ```typescript // frontend/lib/api/yourModule.ts // 1. API URL 동적 설정 (필수) const getApiBaseUrl = (): string => { if (process.env.NEXT_PUBLIC_API_URL) { return process.env.NEXT_PUBLIC_API_URL; } if (typeof window !== "undefined") { const currentHost = window.location.hostname; // 프로덕션: v1.vexplor.com → api.vexplor.com if (currentHost === "v1.vexplor.com") { return "https://api.vexplor.com/api"; } // 로컬 개발 if (currentHost === "localhost" || currentHost === "127.0.0.1") { return "http://localhost:8080/api"; } } return "/api"; }; const API_BASE = getApiBaseUrl(); // 2. API 함수 작성 export async function getYourData(id: number): Promise> { try { const response = await fetch(`${API_BASE}/your-endpoint/${id}`, { credentials: "include", }); return await response.json(); } catch (error: any) { return { success: false, error: error.message, }; } } ``` ## 환경별 URL 매핑 API 클라이언트는 자동으로 환경을 감지합니다: | 현재 호스트 | 백엔드 API URL | | ---------------- | ----------------------------- | | `v1.vexplor.com` | `https://api.vexplor.com/api` | | `localhost:9771` | `http://localhost:8080/api` | | `localhost:3000` | `http://localhost:8080/api` | ## 체크리스트 코드 작성 시 다음을 확인하세요: - [ ] `fetch('/api/...')` 직접 사용하지 않음 - [ ] 적절한 API 클라이언트 함수를 import 함 - [ ] API 응답의 `success` 필드를 체크함 - [ ] 에러 처리를 구현함 - [ ] 새로운 API가 필요하면 `lib/api/` 에 함수 추가 ## 예외 상황 다음 경우에만 `fetch`를 직접 사용할 수 있습니다: 1. **외부 서비스 호출**: 다른 도메인의 API 호출 시 2. **특수한 헤더가 필요한 경우**: FormData, Blob 등 이 경우에도 가능하면 전용 API 클라이언트 함수로 래핑하세요. ## 실제 적용 예시 ### 플로우 위젯 ([FlowWidget.tsx](mdc:frontend/components/screen/widgets/FlowWidget.tsx)) ```typescript // ❌ 이전 코드 const stepsResponse = await fetch(`/api/flow/definitions/${flowId}/steps`); const connectionsResponse = await fetch(`/api/flow/connections/${flowId}`); // ✅ 수정된 코드 const stepsResponse = await getFlowSteps(flowId); const connectionsResponse = await getFlowConnections(flowId); ``` ### 플로우 가시성 패널 ([FlowVisibilityConfigPanel.tsx](mdc:frontend/components/screen/config-panels/FlowVisibilityConfigPanel.tsx)) ```typescript // ❌ 이전 코드 const stepsResponse = await fetch(`/api/flow/definitions/${flowId}/steps`); // ✅ 수정된 코드 const stepsResponse = await getFlowSteps(flowId); ``` ## 참고 자료 - [API 클라이언트 공통 설정](mdc:frontend/lib/api/client.ts) - [플로우 API 클라이언트](mdc:frontend/lib/api/flow.ts) - [API URL 유틸리티](mdc:frontend/lib/utils/apiUrl.ts)