Skip to content

서버 에러 통합

15.3.1. 백엔드 에러 응답 형식

TQS 백엔드 표준 에러 응답은 다음 구조를 따릅니다. 프론트엔드는 이 형식에 맞춰 에러를 처리해야 합니다.

typescript
// src/types/api.ts
interface ApiErrorResponse {
  errorCode: string        // 에러 코드 (예: 'VALIDATION_ERROR', 'CONFLICT')
  message: string          // 사용자 대상 메시지
  fieldErrors?: {          // 필드별 검증 에러 (선택)
    field: string
    message: string
  }[]
}
필드필수 여부설명
errorCode필수에러 분류 코드
message필수전역 에러 메시지
fieldErrors선택필드 단위 검증 실패 목록
  • fieldErrors는 폼 제출 시 서버 측 검증 실패인 경우에만 포함됩니다.
  • errorCode는 프론트엔드에서 에러 유형별 분기 처리에 사용합니다.

15.3.2. 필드별 에러 매핑

서버에서 반환된 fieldErrors는 폼의 errors 상태에 매핑합니다.

typescript
// src/utils/mapServerErrors.ts
import type { ApiErrorResponse } from '@/types/api'

export function mapFieldErrors(
  response: ApiErrorResponse
): Record<string, string> {
  const errors: Record<string, string> = {}

  if (response.fieldErrors) {
    for (const fieldError of response.fieldErrors) {
      errors[fieldError.field] = fieldError.message
    }
  }

  return errors
}

폼 제출 핸들러에서 다음과 같이 적용합니다.

typescript
import { mapFieldErrors } from '@/utils/mapServerErrors'
import axios from 'axios'

async function handleSubmit() {
  isSubmitting.value = true
  errors.value = {}

  try {
    await createUser(form.value)
  } catch (e) {
    if (axios.isAxiosError(e) && e.response?.data) {
      const serverError = e.response.data as ApiErrorResponse
      errors.value = mapFieldErrors(serverError)
    }
  } finally {
    isSubmitting.value = false
  }
}
  • 서버의 field 값은 폼 객체의 키와 일치해야 합니다.
  • 백엔드와 프론트엔드 간 필드명 규칙을 사전에 합의합니다.

15.3.3. 글로벌 에러 처리

fieldErrors에 매핑되지 않는 에러는 글로벌 에러로 처리합니다. 토스트 알림 또는 폼 상단 배너로 표시합니다.

typescript
import { useToast } from '@/composables/useToast'

const { showToast } = useToast()

async function handleSubmit() {
  isSubmitting.value = true
  errors.value = {}

  try {
    await createUser(form.value)
  } catch (e) {
    if (axios.isAxiosError(e) && e.response?.data) {
      const serverError = e.response.data as ApiErrorResponse

      const fieldErrors = mapFieldErrors(serverError)
      if (Object.keys(fieldErrors).length > 0) {
        errors.value = fieldErrors
      } else {
        showToast({ type: 'error', message: serverError.message })
      }
    } else {
      showToast({ type: 'error', message: '요청 처리 중 오류가 발생했습니다.' })
    }
  } finally {
    isSubmitting.value = false
  }
}
에러 유형표시 방식예시
필드 검증 에러필드 하단 인라인"이미 사용 중인 이메일입니다."
비즈니스 로직 에러토스트 알림"일일 등록 한도를 초과했습니다."
네트워크/서버 에러토스트 알림"요청 처리 중 오류가 발생했습니다."

15.3.4. 에러 초기화

사용자가 폼을 수정하면 관련 에러를 자동으로 초기화합니다. 재제출 시에는 전체 에러를 초기화합니다.

typescript
import { watch } from 'vue'

// 개별 필드 변경 시 해당 에러 초기화
watch(
  () => form.value.email,
  () => {
    if (errors.value.email) {
      delete errors.value.email
    }
  }
)

// 범용 초기화 — 폼 전체 감시
watch(
  form,
  () => {
    errors.value = {}
  },
  { deep: true }
)
  • 필드 단위 초기화는 특정 필드의 에러만 제거하여 다른 필드의 에러 메시지를 유지합니다.
  • 폼 전체 감시는 모든 에러를 일괄 제거하므로 간결하지만, 다른 필드의 에러도 사라지는 점에 유의합니다.
  • 프로젝트 요구사항에 따라 적절한 전략을 선택합니다.

TIENIPIA QUALIFIED STANDARD