돌멩이 하나/에러는 미래의 연봉

OpenAPI 스펙을 기반으로 자동 생성한 API 타입 불일치 문제

미래에서 온 개발자 2025. 3. 2. 19:26

프로젝트에서 OpenAPI 스펙을 기반으로 백엔드와 API 통신에 필요한 타입 스키마와 fetcher 함수 등을 자동으로 생성해주는 orval을 사용하고 있다. 그런데 데이터 스키마 중 일부 타입이 백엔드에서 의도한 것과 다르게 내려오는 부분을 발견했다. 

 

export type DataStatisticsUpdatedAt = string | null;

export interface DataStatistics {
  data: DataStatisticsDataItem[];
  updated_at?: DataStatisticsUpdatedAt;
}

 

백엔드 개발자에게 `updated_at` 필드가 optional인 이유를 물어봤더니 optional이 아닌 required 필드라고 했다. 그런데 자동 생성된 타입 스키마에서는 옵셔널(?) 표시가 붙어있었다. 이로 인해 프론트엔드 코드에서는 불필요한 타입 체크를 해야만 타입스크립트의 불평 없이 코드를 사용할 수 있었다. 불필요한 타입 체크를 하는 코드가 늘어나는 것도 문제지만, 근본적으로 클라이언트 <-> 서버 사이의 약속으로 사용하고 있는 OpenAPI code generator의 어떤 부분을 믿을 수 없다는 것이 문제였다. 

 

백엔드 개발자가 문제의 원인을 찾아봐주었고, python에서 데이터 검증과 설정 관리를 위해 사용하는 pydantic이라는 라이브러리에서 모델 정의시 필드에 기본값이 설정되어 있으면 해당 필드를 OpenAPI 스키마 생성 과정에서 자동으로 옵셔널 필드로 변환하는 동작이 있다는 것을 알게 되었다. 위의 예시 모델의 경우 `updated_at` 필드에 null을 기본값으로 설정했기 때문에 해당 필드가 옵셔널 필드가 된 것이었다. 문서에서 json_schema_serialization_defaults_required 설정의 디폴트 값이 false였고, 이를 true로 바꾼 후 다시 orval을 실행했더니 `updated_at` 필드의 옵셔널 표시가 사라졌다. 

 

 

Configuration - Pydantic

Data validation using Python type hints

docs.pydantic.dev

 

 

이번 이슈를 통해 OpenAPI 스키마가 항상 실제 API 동작을 100% 정확하게 반영하지 않을 수 있다는 점을 알게 되었다. 하지만 이 문제를 인지하자마자 백엔드 개발자가 빠르게 대처해준 덕에 서로 간의 약속인 API 스펙이 보다 견고해질 수 있었다. 팀원의 존재 소중하다. 

 

그나저나 타입스크립트 없으면 어떻게 코드를 작성할까...? 타입스크립트 절대 못 잃어...