FrontEND/vue

TypeScript에서 안전하게 API 응답 객체 처리 및 Axios + DTO 구조로 타입 안정성 높이기

mingmingIT 2025. 4. 29. 10:41

프론트엔드 개발에서 외부 API와의 통신은 필수입니다.
하지만 API 응답의 타입이 예측과 다르거나 누락될 경우, 예상치 못한 에러가 발생할 수 있습니다.
특히 TypeScript 환경에서는 타입 안정성을 확보하지 않으면 undefined 참조 오류가 쉽게 발생하죠.

이번 포스팅에서는 다음 두 가지에 대해 실제 예제를 통해 정리합니다:

  1. Axios로 API 호출 시 안전하게 응답 처리하는 방법
  2. DTO 구조를 활용하여 타입 안정성을 높이는 실무 방식

✅ 1. API 응답 처리에서 흔히 생기는 문제

예를 들어 아래와 같은 사용자 API가 있다고 해봅시다:

GET /api/user/1
{
  "id": 1,
  "name": "Alice",
  "email": "alice@example.com"
}

타입을 선언하지 않고 바로 사용하면 아래와 같은 위험이 있습니다.

axios.get('/api/user/1').then((res) => {
  console.log(res.data.name.toUpperCase()) // ❌ name이 undefined일 수도 있음
})

이런 경우 다음과 같은 오류를 만날 수 있습니다:

Object is possibly 'undefined'

🔐 2. TypeScript + Axios 환경에서 안전하게 처리하는 방법

2-1. 응답 타입을 미리 정의

interface UserResponse {
  id: number
  name: string
  email: string
}

2-2. Axios 제네릭으로 타입 지정

import axios from 'axios'

async function fetchUser(userId: number): Promise<UserResponse> {
  const response = await axios.get<UserResponse>(`/api/user/${userId}`)
  return response.data
}

이제 response.data는 UserResponse 타입으로 명확하게 지정되므로, IDE 자동완성도 되고, 타입 오류도 방지됩니다.


🧱 3. DTO 패턴을 사용해 타입 안정성 강화하기

DTO(Data Transfer Object)는 API에서 받아온 데이터 구조를 명확히 선언하고, 불필요한 데이터 또는 가공된 형태로 다룰 수 있는 패턴입니다.

3-1. DTO 정의

export class UserDTO {
  id: number
  name: string
  email: string

  constructor(data: any) {
    this.id = data.id ?? -1
    this.name = data.name ?? '이름없음'
    this.email = data.email ?? ''
  }

  getDisplayName(): string {
    return this.name.toUpperCase()
  }
}

✅ ??를 통해 null 또는 undefined에 대한 기본값 설정까지 포함


3-2. API 응답을 DTO로 변환

async function fetchUserDto(userId: number): Promise<UserDTO> {
  const res = await axios.get(`/api/user/${userId}`)
  return new UserDTO(res.data)
}

이렇게 하면 UserDTO 인스턴스를 통해 타입 안정성을 높이고, 필요한 가공 함수(getDisplayName)까지 포함시킬 수 있습니다.


✅ 장점 요약

항목 DTO 패턴 사용 전 DTO 패턴 사용 후
타입 안정성 낮음 (any or unknown) 높음 (정의된 타입 + 기본값 처리)
유지보수성 낮음 높음
데이터 가공 외부에서 처리 내부 메서드로 처리 가능

🔄 4. 예시: 안전하게 API 호출 + DTO 사용

const loadUser = async () => {
  try {
    const user = await fetchUserDto(1)
    console.log(user.getDisplayName()) // ALICE
  } catch (e) {
    console.error('사용자 정보를 불러오는 데 실패했습니다.', e)
  }
}
  • 응답 누락 필드 방지
  • 기본값 처리 포함
  • 객체 메서드까지 활용 가능

🧩 마무리

TypeScript 환경에서 API 데이터를 다룰 때 가장 중요한 포인트는 타입 안전성 확보입니다.
Axios의 제네릭 기능과 DTO 패턴을 조합하면:

  • 오류 없는 안전한 코드 작성 가능
  • 유지보수성 향상
  • 명확한 구조로 개발 협업이 쉬워짐

실무에서는 반드시 DTO 패턴을 활용해 API 응답을 다루는 습관을 들이세요.