eatthefrog
GraphQL 타입 불일치 문제를 사전에 방지하는 방법 본문

스키마와 Resolver의 타입이 어긋나는 문제는 생각보다 자주 발생합니다. 특히 날짜, 통계 데이터, 복합 구조를 다룰 때 더 빈번합니다. 아래는 동일한 문제를 예방하기 위한 실전 전략들입니다.
1. 스키마 설계 시 고려해야 할 기준
1) 필드의 최종 형태(Serialized Form)를 먼저 정의하기
GraphQL 스키마는 클라이언트가 받게 되는 최종 데이터 형태를 기준으로 설계해야 합니다.
예를 들어 날짜 관련 데이터를 API 내부에서는 { year, month } 형태로 계산하더라도,
클라이언트가 문자열 "2025-11"을 받는 것이 더 직관적이라면 스키마도 String!으로 정의해야 합니다.
반대로 { year: number; month: number } 구조가 더 설명적이라면 스키마도 객체 타입으로 정의하는 것이 맞습니다.
핵심은 다음 한 줄입니다.
“내부 구현 기준이 아니라, 외부 소비자 기준으로 스키마를 설계하자.”
2) 내부 모델과 GraphQL 타입을 분리하기
많은 프로젝트가 Entity(Model) 구조를 그대로 GraphQL 타입에 매핑하려고 합니다.
하지만 이는 타입 불일치를 유발하는 대표적인 원인입니다.
- 내부 모델: { year: number, month: number }
- GraphQL 스키마: "YYYY-MM" 문자열
- Resolver: 내부 모델 → 스키마에 맞게 변환하는 역할
이렇게 명확히 분리해두면 타입 충돌 가능성을 크게 줄일 수 있습니다.
3) 유지보수성을 위해 Custom Scalar를 고려하기
날짜 타입은 문자열로 처리할 수도 있지만, 팀의 스타일에 따라 custom scalar로 더 명확하게 표현할 수도 있습니다.
예:
scalar YearMonth
이렇게 선언해두면
- 문자열
- 객체
- 날짜 객체
중 어떤 형태를 사용할지 팀 차원의 합의가 쉬워집니다.
2. Resolver 단계에서의 직렬화 전략
1) 스키마 타입에 맞게 데이터를 변환하는 계층을 분리하기
Resolver에서 스키마에 맞는 값을 직접 가공하면 코드가 점점 지저분해집니다.
대신, 직렬화를 담당하는 별도 유틸리티를 두는 것이 좋습니다.
예:
// serializer.ts
export const serializeYearMonth = (dateObj) =>
`${dateObj.year}-${String(dateObj.month).padStart(2, "0")}`;
Resolver는 깔끔하게 유지됩니다.
date: (parent) => serializeYearMonth(parent.date)
이런 구조는 테스트도 훨씬 쉽습니다.
2) nullable 여부를 정확하게 정의하기
GraphQL의 String vs String!은 완전히 다른 의미입니다.
- String → 문자열 또는 null 허용
- String! → 반드시 문자열이어야 함
만약 데이터가 null이 될 수 있다면 반드시 스키마에 반영해야 합니다.
스키마와 실제 데이터가 다르면 직렬화 에러가 발생합니다.
3) 데이터를 반환하기 전에 스키마와 비교하는 Pre-check 도입
프로덕션 배포 전 아래 체크를 추가하면 타입 불일치를 조기에 발견할 수 있습니다.
- Jest에서 Resolver 반환값의 타입 검증
- GraphQL Codegen을 사용해 TypeScript 타입을 자동 생성
- CI에서 스키마-리졸버 타입 검증을 필수 단계로 설정
이런 자동화 조치는 “스키마는 문자열인데 객체가 반환되는” 문제를 미리 차단하는 데 큰 도움이 됩니다.
3. 타입 불일치를 예방하는 팀 차원의 Best Practice
✔ 1) 스키마 변경 전에 클라이언트 영향도를 반드시 체크하기
GraphQL의 가장 강력한 장점은 “명시적 스키마”입니다.
스키마가 변경되면, 해당 스키마를 소비하는 클라이언트에도 반드시 영향이 있습니다.
“스키마 변경은 API 버전 업데이트와 거의 동일하다”는 인식이 필요합니다.
✔ 2) 스키마 → Resolver → 내부 로직 흐름을 문서화
특히 날짜, 통계, 계산 로직 같은 복잡한 데이터는
스키마 설계 → 내부 모델 → 직렬화 전략
순으로 문서화하면 팀이 쉽게 따라올 수 있습니다.
✔ 3) GraphQL Codegen 적극 사용하기
Codegen으로 타입을 자동 생성하면:
- 스키마가 바뀌면 프론트 & 백엔드 타입이 자동 갱신
- “타입 불일치” 문제를 컴파일 단계에서 발견 가능
직렬화 관련 버그가 크게 줄어듭니다.
결론
이번 문제는 단순한 버그처럼 보이지만, 근본적으로는 스키마 설계와 직렬화 전략이 일관되지 않았기 때문에 발생한 타입 불일치 이슈였습니다.
지금 정리한 내용처럼
- 스키마를 소비자 중심으로 설계하고
- 내부 모델과 GraphQL 타입을 분리하고
- 직렬화 전략을 명확하게 두고
- 자동화된 타입 체크를 도입하면
이런 문제는 거의 발생하지 않습니다.
'백엔드 노트' 카테고리의 다른 글
| 몽고DB - English Keyword (0) | 2025.11.18 |
|---|---|
| 몽고DB) DOCUMEMNT DATABASE (0) | 2025.11.18 |
| MongoDB Compass indexes (0) | 2025.11.11 |
| CI/CD 개발 프로세스 (0) | 2025.06.24 |
| GraphQL 핵심 요약 (2) | 2025.06.18 |