진형주@hyoungjoojin · Sep 13, 2026Claude Code(으)로 작성

서버 빌드 → OpenAPI → Orval, 순서를 어기면 생기는 일

프론트에서 방금 추가한 API가 자동완성에 안 잡힌다는 얘기가 두 번 나왔다. 두 번 다 같은 원인이라 정리해둔다.

파이프라인

타입은 손으로 쓰지 않는다. 서버에서 프론트까지 한 방향으로 흐른다.

Spring REST Docs 테스트
   ↓  ./gradlew build (openapi3 태스크)
docs/api/openapi3.yaml
   ↓  pnpm orval
apps/web/src/api/__generated__/

그래서 서버를 빌드하지 않으면 스펙이 안 바뀌고, 스펙이 안 바뀌면 프론트 타입도 안 바뀐다. API를 추가했는데 안 보인다면 거의 항상 서버 빌드를 건너뛴 것이다.

두 앱을 같이 건드릴 때 순서는 고정이다.

cd apps/server && ./gradlew build   # 먼저
cd apps/web    && pnpm build        # 나중

자주 걸리는 지점

1. REST Docs 테스트를 안 썼다

openapi3.yaml은 컨트롤러를 스캔해서 만들어지는 게 아니라 문서화 테스트의 결과물이다. 테스트를 안 쓰면 엔드포인트가 존재해도 스펙에 안 올라간다. 컨트롤러만 만들고 끝내면 프론트에서는 없는 API다.

2. openapi3.yaml을 직접 고쳤다

생성물이다. 손으로 고쳐봐야 다음 서버 빌드에 덮어써진다. __generated__/ 아래도 마찬가지다.

3. 필드 이름을 스니펫 파일이 아닌 곳에서 바꿨다

API 모델의 필드 설명은 도메인별 snippets 디렉터리에 분리해둔다. 문서와 구현을 따로 움직이게 하려는 의도적인 구조다.

CI가 잡아준다

웹·서버 CI 둘 다 빌드 후 git status --porcelain을 확인하고, 파일이 하나라도 바뀌면 실패한다.

생성물을 커밋하지 않았다는 뜻이기 때문이다. 즉 로컬에서 빌드를 안 돌리고 올리면 CI가 반드시 잡는다. 커밋 전에 돌리는 게 결국 빠르다.

# 서버
./gradlew build          # spotlessApply 포함

# 웹
pnpm format && pnpm lint && pnpm build

./gradlew build가 spotlessApply를 자동으로 적용하기 때문에, 포맷 차이만으로도 CI가 떨어질 수 있다.

댓글

아직 댓글이 없습니다.