안정적인 API 연동
개발할 때 갑작스런 인원 변화로 내가 할 수 있는 역량 보다 더 많은 역할을 해야 할 경우가 온다. 이번 프로젝트가 그런 경우였다. 급하게 AI 를 이용해서 개발을 진행하다 보니. 모든 파트를 완벽하게 이해도 못하고, 백엔드 쪽에서는 API를 구상하고 생성한 것을 프론트에서 정확한 피드백을 해주어야 하는데. 뭔가 적절한 타이밍에 백엔드 팀원들에게 피드백을 못 준 것 같다. 내 요구가 늦어지면, 서버 개발이 늦어지고. 또 그러면 API 나오는 속도가 늦어져서 연동이 늦어지고… 하는 악순환이다..
또 API 연동을 하면서 API에 따라 내 디자인을 수정하기도 해야 하고, 하면서 UX 도 생각을 해야 하는데, 머리속이 정리가 잘 안되어있었어서 QA할 때 피드백이 겁나 많이 들어왔다. 그래서 지선생님께 이런 상황에서 어떻게 해쳐나가야 할지 지혜를 얻고 싶다.
혼자서 API 연동을 안정적으로 하는 방법
프론트 팀원이 빠진 상황에서 혼자 API 연동을 맡게 되면, 단순히 기능 구현보다 “누락 없이 안정적으로 붙이는 것”이 훨씬 중요해진다. 이때 핵심은 감으로 개발하지 않고, 흐름을 명확하게 구조화하는 것이다.
1. API 명세를 코드처럼 다루기
가장 먼저 해야 할 것은 API 명세를 문서가 아니라 “계약”으로 보는 것이다.
- 요청 URL, method, params, body
- 응답 데이터 구조
- 에러 응답 형태
이걸 그냥 읽고 넘어가는 게 아니라, 타입으로 먼저 정의한다.
// types/house.ts
export interface HouseListResponse {
houseId: number;
houseType: string;
rentType: string;
deposit: number;
monthlyCost: number;
}
이렇게 하면 연동하면서 “이 필드 뭐였지?” 하는 순간 자체가 줄어든다. 근데 백엔드도 바빠서 명세서 수정 안해주고.. 난 그냥 그거 믿고 개발하고… 흐아아악
2. API 호출 레이어 분리 (절대 컴포넌트에서 직접 호출하지 않기)
혼자 할수록 구조를 더 지켜야 한다.
// lib/api/house.ts
import axios from '@/lib/axios';
export const getHouseList = async () => {
const res = await axios.get('/houses');
return res.data;
};
컴포넌트에서는 이 함수만 사용한다.
const data = await getHouseList();
이렇게 해야 나중에 수정할 때 한 군데만 고치면 된다. 이건 이번에는 AI로 개발을 해서 잘 지켜진것 같다. 근데 NEXT.js의 백엔드 요청 구조는 아직 이해가 잘 안된다.. 프록시 서버에 대한 공부를 해야겠다.
3. 상태 관리와 API 연결 기준 명확히 하기
Zustand를 쓴다면 “API 호출 → store 저장 → UI 렌더” 흐름을 고정한다.
// store/houseStore.ts
import { create } from 'zustand';
interface HouseState {
houses: HouseListResponse[];
fetchHouses: () => Promise<void>;
}
export const useHouseStore = create<HouseState>((set) => ({
houses: [],
fetchHouses: async () => {
const data = await getHouseList();
set({ houses: data });
},
}));
이렇게 하면 컴포넌트는 데이터 흐름을 신경 안 써도 된다.
4. 로딩 / 에러 상태는 무조건 분리
혼자 개발할 때 가장 많이 놓치는 부분이 이거다.
- 로딩 상태 없음 → UX 망가짐
- 에러 처리 없음 → 디버깅 지옥
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
AI 추천처럼 15~30초 걸리는 API라면 특히 중요하다.
- 로딩 UI (스켈레톤 or 메시지)
- 타임아웃 대비 메시지
- 실패 시 재시도 버튼
이건 “기능”이 아니라 “기본값”이다. 맞아.. 지선생.. 근데 로딩 UI 넣어야 하는 곳이 너무 많아…
5. API 흐름을 시나리오 단위로 체크
기능 단위가 아니라 “사용자 행동” 기준으로 점검해야 한다.
예:
- 검색 → 리스트 노출 → 상세 클릭 → 지도 이동
- 매물 등록 → 이미지 업로드 → 생성 요청 → 완료
이걸 직접 하나씩 실행하면서 체크한다.
특히 놓치기 쉬운 부분:
- query param 유지 (keyword, filter)
- houseId 상태 유지
- 뒤로가기 시 상태 복원
6. 백엔드와 맞지 않는 부분은 바로 로그로 확인
감으로 맞추려고 하면 시간 날린다.
확인 순서:
- 요청 payload 콘솔 찍기
- 네트워크 탭 확인
- 응답 구조 확인
- 타입과 비교
console.log('request', payload);
console.log('response', res.data);
특히 좌표(lat/lng 뒤집힘), 필드명 mismatch 같은 건 여기서 바로 잡힌다. 무한 로그 넣어줘!@!!!!!!!!
7. 비동기 흐름은 항상 “순서” 기준으로 생각
예: 이미지 업로드
- presigned URL 요청
- S3 업로드
- DB 저장 요청
이걸 동시에 처리하면 무조건 꼬인다.
await uploadToS3();
await createHouse();
순서를 명확히 유지해야 한다.
8. “임시 UI → 실제 API” 교체 전략 사용
처음부터 API 붙이려고 하면 속도 안 나온다.
- mock 데이터로 UI 완성
- API 함수 연결
- 데이터 구조 맞추기
이 순서가 가장 빠르다. 뭐 목데이터는 UI 할때 다 만드니깐…
9. 체크리스트 기반으로 마무리
혼자 할 때는 기억에 의존하면 반드시 빠진다.
최소 체크리스트:
- API 성공 케이스
- 빈 데이터 케이스
- 에러 케이스
- 로딩 상태
- 뒤로가기 동작
- URL 상태 유지
이거 진짜 그럼.. 그래서 체크리스트 만들었는데 겁나 길어짐..
정리
혼자 API 연동을 잘하는 방법은 결국 하나다.
“구조를 먼저 만들고, 그 구조 안에서만 구현한다”
감으로 붙이면 빠르게 되는 것 같지만, 결국 디버깅에서 시간을 더 쓰게 된다. 특히 지금처럼 추천, 지도, AI 응답이 섞인 서비스에서는 더더욱 흐름 관리가 중요하다.
지금 상황에서는 “빠르게 구현”보다 “안정적으로 반복 가능한 구조”를 만드는 게 더 중요한 선택이다.
생각보다 나 잘하고 있었을 지도..? 많이 지키면서 했당! 뿌듯