AppSpec API 라우트 구조를 먼저 설계한 이유
목차
Week 2 첫날, AppSpec CRUD를 위한 API route handler 3개를 붙였다.
Next.js App Router 기반으로 프로젝트 관련 API를 설계하다 보면, 초반에 파일 구조 잡는 게 생각보다 큰 결정이 된다. 이번에 projects, projects/[projectId], projects/[projectId]/spec 세 개의 route를 한 번에 설계하면서 느낀 것들을 정리해본다.
왜 이 타이밍에 CRUD route부터 잡았나
Week 1이 끝나고 Week 2 첫날에 API route부터 뽑은 건 의도적인 선택이었다. 프론트엔드 팀이 UI 작업에 들어가기 전에 API contract가 먼저 확정되어야 병렬 작업이 가능하다. spec 구조가 불확실한 상태에서 컴포넌트를 먼저 만들면 나중에 데이터 바인딩 단계에서 전부 뜯어고치게 된다. 그래서 이 순서는 팀 입장에서 다음 작업들의 블로킹을 최소화하는 선택이었다.
파일 세 개가 만들어진 모양을 보면 구조가 명확하다.
| 파일 | 역할 | 주요 HTTP 메서드 |
|---|---|---|
api/projects/route.ts |
프로젝트 목록 조회 / 생성 | GET, POST |
api/projects/[projectId]/route.ts |
단일 프로젝트 조회 / 수정 / 삭제 | GET, PUT, DELETE |
api/projects/[projectId]/spec/route.ts |
해당 프로젝트의 AppSpec CRUD | GET, POST, PUT |
spec이 projectId 하위에 nested된 구조를 선택한 것도 트레이드오프가 있었다. spec이 독립 리소스냐, 프로젝트에 종속된 sub-resource냐의 판단이 필요한데 — AppSpec이 프로젝트 없이 단독으로 의미를 가지지 않는다면 nested route가 맞다. URL 레벨에서 소유 관계를 명시해주면 권한 체크나 미들웨어 적용 범위도 훨씬 직관적으로 설계할 수 있다.
App Router route handler 설계할 때 자주 보이는 패턴
Next.js App Router에서 route.ts를 붙이다 보면 몇 가지 패턴이 반복된다.
// apps/web/src/app/api/projects/[projectId]/spec/route.ts
export async function GET(
request: Request,
{ params }: { params: { projectId: string } }
) {
const { projectId } = params;
// projectId를 기준으로 spec 조회
}
export async function POST(
request: Request,
{ params }: { params: { projectId: string } }
) {
const body = await request.json();
// spec 생성 로직
}
params를 두 번째 인자로 받는 구조는 Pages Router의 req.query와 다르게 타입이 명시적으로 잡히기 때문에 좋다. 다만 이 시점에서 팀에게 강조했던 건 두 가지였다.
- 에러 응답 포맷을 통일할 것. 각 handler가 각자 방식으로 에러를 뱉기 시작하면 프론트엔드에서 분기 처리가 지저분해진다.
{ error: string, code: string }같은 공통 타입을 초반에 잡아두는 게 낫다. paramsvalidation을 handler 안으로 끌어들이지 말 것.projectId가 유효한 형식인지, 실제로 존재하는지 같은 체크는 미들웨어나 공통 유틸로 빼는 게 코드 리뷰할 때 훨씬 보기 편하다.
이런 작업의 리뷰 포인트
CRUD route handler를 코드리뷰할 때 내가 주로 보는 것들은 구현 세부사항보다 구조적인 부분이다.
- resource 간 계층 관계가 URL에 정확히 반영되어 있는가
- 각 메서드가 REST 시맨틱을 제대로 따르고 있는가 (
POST가 idempotent하게 쓰이고 있지는 않은지) - 응답 status code가 상황에 맞게 분기되어 있는가 (생성 성공은
201, 찾을 수 없는 리소스는404등) - 인증/인가 체크가 handler 내부 로직이 실행되기 전에 이미 통과되었는가
이번 Week 2 Day 1 작업은 이 구조를 세팅하는 데 집중했고, 이후 spec의 비즈니스 로직은 여기 위에서 계속 쌓아가는 형태가 된다. 뼈대를 제대로 잡아야 나중에 팀원이 기능 추가할 때 어디다 뭘 써야 하는지 헤매지 않는다.
다음은 이 route들과 연결되는 DB 레이어, 그리고 실제 spec 데이터 모델 설계 쪽으로 넘어간다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.