Axios 응답과 데이터 안정성: Date 타입은 왜 string으로 올까?

rabbit jack·2025년 6월 27일

Typescript

목록 보기
5/5

axios를 이용한 통신은 주로 아래와 같은 방식으로 이루어 진다.

const res : MovieDTO = await axios.get('/api/movies', { headers: { Authorization: "Bearer token" } });

return res.data;

이때 서버에서 도착하는 JSON 응답의 형태는 아래와 같다.

{
  "id": 1,
  "title": "인터스텔라",
  "release_date": "2025-06-27T00:00:00.000Z"
}

해당 본문의 응답 자체는 text 형태로 들어오며, 이를 axios가 아래와같이 자동 파싱을 진행한다.

JSON.parse(responseText);

이때 모든 값은 기본 Javascript 타입으로 바뀌게 되는데,

DTO에서 release_date의 타입을 Date로 적용했을지라도, 그냥 string으로 변하게된다.

JSON은 primitive 타입만 직렬화/복원하며, Date는 참조형이기 때문이다.

즉, 서버측에서 Date 타입으로 전송했을지라도, 클라이언트에서는string 타입으로 인식하게된다.

const res : MovieDTO = await axios.get('/api/movies', { headers: { Authorization: "Bearer token" } });

console.log(typeof res.data);	// string

해결책

1. 직접 파싱하기

아래 방법으로 직접 파싱을 진행 할 수 있다.

if(res.data?.release_date){
	res.data.release_date = new Date(res.data.release_date)   
}

2. response interceptor

응답을 가로채서 변환후 반환하는 방법도 가능하다.

api.interceptors.response.use((response) => {
  if (response.data?.release_date) {
    response.data.release_date = new Date(response.data.release_date);
  }
  return response;
});

하지만 이 방법은, 응답 형태가 배열 및 중첩 오브젝트일 경우 사용할 수 없다.
또한 필드명이 release_datedeletated_at, created_at일 경우에도 마찬가지이다.

3. 재귀탐색 + 추론

필드를 하나하나 재귀적으로 탐색하며, 아래 조건이 충족하면 Date 타입으로 변환을 시도한다.
1. Key 이름이 다음 중 하나를 만족:
- date로 시작(/^date/i)
- at, date, At, Date 등으로 끝남(/(at|date)$/i)
2. Value가 ISO 8601 문자열 형태(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)

function isLikelyDateKey(key: string): boolean {
  return /^date/i.test(key) || /(at|date)$/i.test(key);
}

function isISODateString(value: any): boolean {
  return typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value);
}

function reviveDates(obj: any): any {
  if (Array.isArray(obj)) {
    return obj.map(reviveDates);
  }

  if (obj !== null && typeof obj === 'object') {
    const newObj: any = {};
    for (const [key, value] of Object.entries(obj)) {
      if (isLikelyDateKey(key) && isISODateString(value)) {
        newObj[key] = new Date(value);
      } else {
        newObj[key] = reviveDates(value); // 재귀
      }
    }
    return newObj;
  }

  return obj;
}

문제점

가령 매일의 경기 결과를 보관하는 필드의 이름이 date_result이며,

득점-실점-최종점수 의 형식으로 보관하기 위해 2-1-4 같은 양식을 쓴다면

위 알고리즘은 해당 타입을 자동으로 Date로 인식하게 된다.

이렇듯 프로그래밍에서 추론식으로 문제를 해결하는 방식은 매우 위험하다.

4. 명시적으로 변환

현업에서는 절대 추측하지 않는다.

서버에서는 날짜를 반드시 ISO 형식으로 명시적으로 반환한다.
(예 : "2025-06-27T14:34:00.000Z" ← ISO 8601 형식 )

프론트 개발자는 YYYY-MM-DDTHH:mm:ss.sssZ 형식인지 점검하고, Date 변환 가능 여부를 판별한다.

마무리

Typescript를 쓰더라도, Javascript에서 겪던 타입 혼동 문제에서 완전히 자유로울 순 없다.

특히 Dto 명세의 작성을 class가 아닌 interface로 할 경우엔, 런타임중 타입 비교조차 힘들어진다.

Node.js기반 환경에서는 런타임중 생성되는 데이터의 타입을 항상 의심해야 하며,

이와중에 생산성을 챙기기 위한 설계역량을 꾸준히 키워나가야한다.

0개의 댓글