--- name: dev-api-state description: | API 연동 패턴(useFetch / useAsyncData / $fetch)과 Pinia 상태관리 코드를 상황에 맞게 자동 선택·생성합니다. BFF 패턴, 에러 핸들링, 로딩 상태를 포함합니다. 다음 상황에서 반드시 사용하세요: - "이 API 연동 + 스토어 만들어줘", "Pinia store 작성해줘" - "API 데이터 페칭 어떻게 해?", "useFetch vs useAsyncData 언제 써?" - API 키 보호를 위한 BFF(server/api/) 패턴이 필요할 때 --- # API 연동 & 상태관리 (dev-api-state) API 스펙 → useFetch/useAsyncData 패턴 선택 → Pinia Setup Store 코드 자동 생성. ## 언제 사용하는가 - 새 API 연동 코드와 Pinia 스토어를 함께 작성할 때 - `useFetch` / `$fetch` / `useAsyncData` 중 적절한 패턴을 결정할 때 - API 키를 클라이언트에 노출하지 않기 위한 BFF 패턴이 필요할 때 ## 데이터 페칭 패턴 선택 기준 | 상황 | 권장 패턴 | |---|---| | SSR 페이지 초기 데이터 | `useAsyncData` + `$fetch` | | 컴포넌트 마운트 후 데이터 | `useFetch` | | 사용자 액션으로 트리거 | `$fetch` (직접 호출) | | API 키 보호 필요 | `server/api/` BFF + `useFetch` | | 복잡한 캐싱/의존성 | `useAsyncData` with key | --- ## 작업 순서 ### Phase 1: API 스펙 파악 1. 엔드포인트, 요청/응답 타입을 파악한다. 2. 아래를 확인한다: - 인증 헤더 필요 여부 - API 키 노출 위험 여부 → BFF 패턴 적용 - 캐시 전략 (항상 최신 vs TTL) ### Phase 2: 타입 정의 ```ts // types/product.ts export interface Product { id: string name: string price: number imageUrl: string } export interface ProductListResponse { data: Product[] total: number page: number } ``` ### Phase 3: BFF 레이어 (필요 시) API 키 보호가 필요한 경우 server/api/ 경유: ```ts // server/api/products/index.get.ts export default defineEventHandler(async (event) => { const query = getQuery(event) const response = await $fetch( `${process.env.API_BASE}/products`, { headers: { 'x-api-key': process.env.API_KEY! }, query, } ) return response }) ``` ### Phase 4: Pinia Setup Store 생성 Setup Store 패턴을 기본으로 사용한다: ```ts // stores/product.ts import type { Product } from '~/types/product' export const useProductStore = defineStore('product', () => { const items = ref([]) const isLoading = ref(false) const error = ref(null) const fetchProducts = async (page = 1) => { isLoading.value = true error.value = null try { const { data } = await useFetch('/api/products', { query: { page } }) items.value = data.value?.data ?? [] } catch (e) { error.value = e instanceof Error ? e.message : '알 수 없는 오류' } finally { isLoading.value = false } } return { items, isLoading, error, fetchProducts } }) ``` ### Phase 5: 컴포넌트 연결 예시 ```vue ``` --- ## 출력 형식 ``` ## API 연동: <기능명> ### 선택된 패턴 - 페칭: useFetch | useAsyncData | $fetch - BFF: 사용 | 미사용 - 이유: [선택 근거] ### 파일 목록 - `types/.ts` - `server/api/...` (BFF 사용 시) - `stores/.ts` ### 코드 [타입 → BFF → 스토어 → 컴포넌트 순] ```