safeFetch μœ ν‹Έν•¨μˆ˜ λ§Œλ“€κΈ°(1) : Error 클래슀 μ •μ˜

2025. 12. 12. 00:30ㆍTrouble Shooting & Issues/Linkiving

λ°˜μ‘ν˜•

 

βœ”οΈ FetchError : 응닡 λ°›λŠ” 쀑 λ°œμƒν•œ μ—λŸ¬ 클래슀 생성
βœ”οΈ TimeoutError : μ§€μ •λœ μ‹œκ°„ λ‚΄ 응닡을 λ°›μ§€ λͺ»ν–ˆμ„ λ•Œ λ°œμƒν•˜λŠ” μ—λŸ¬ 클래슀 생성
βœ”οΈ ParseError : 응닡은 λ°›μ•˜μœΌλ‚˜, νŒŒμ‹± 쀑 λ°œμƒν•œ μ—λŸ¬ 클래슀 생성
βœ”οΈ Errorλ₯Ό μƒμ†λ°›μœΌλ©°, constructor μƒμ„±μž ν•¨μˆ˜λ‘œ super(message)둜 ν‘œμ€€ μ—λŸ¬ μ΄ˆκΈ°ν™”, 각 ν΄λž˜μŠ€μ— λ§žλŠ” μΈμŠ€ν„΄μŠ€ 지정을 ν•œλ‹€.

λͺ©μ°¨

1. safeFetch: μ„œλ²„μš© μ•ˆμ „ν•œ fetch ν•¨μˆ˜

2. FetchError : 응닡 λ°›λŠ” 쀑 λ°œμƒν•œ μ—λŸ¬

3. TimeoutError : 응닡이 μ§€μ •λœ μ‹œκ°„ 내에 μ˜€μ§€ μ•Šμ•˜μ„ λ•Œμ˜ μ—λŸ¬

4. ParseError : 응닡은 λ°›μ•˜μœΌλ‚˜, νŒŒμ‹± 쀑 λ°œμƒν•œ μ—λŸ¬

5. λ…Έμ…˜ λ¬Έμ„œν™”

 


1. safeFetch: μ„œλ²„μš© μ•ˆμ „ν•œ fetch ν•¨μˆ˜

이건 사싀 μ—¬κΈ°μ €κΈ° μ•Œμ•„λ³΄κΈ°λ³΄λ‹€λŠ” 이전에 주먹ꡬꡬ둜 μž‘μ„±ν–ˆλ˜ 기얡을 λ°”νƒ•μœΌλ‘œ ai 기반으둜 μ‹œλ„ν•΄λ³΄λŠ” 것이닀.

μš°μ„  λ‹Ήμž₯ api에 μ•½ν•˜κΈ°λ„ ν•˜κ³ .. μ“Έλͺ¨κ°€ 없을지라도 ν•˜λ‚˜ν•˜λ‚˜ μžμ„Έν•˜κ²Œ μ•Œμ•„λ³΄λ©΄μ„œ μˆ˜μ •ν•˜κ±°λ‚˜ μ—†μ• κ±°λ‚˜ 라이브러리λ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜ μΆ”κ°€ν•˜κ±°λ‚˜ ν•  수 μžˆμ„ 것이닀.

 

μš°μ„  μ—λŸ¬κ°€ λ°œμƒν–ˆμ„ 경우, μ—λŸ¬ λ°”λ””λ₯Ό μ„ΈνŒ…ν•˜λŠ” Error ν΄λž˜μŠ€λ“€μ„ μž‘μ„±ν•΄λ³΄μž.


2. FetchError : 응닡 λ°›λŠ” 쀑 λ°œμƒν•œ μ—λŸ¬

HTTP 응닡이 okκ°€ μ•„λ‹ˆκ±°λ‚˜(200~299 λ²”μœ„κ°€ μ•„λ‹˜) λ„€νŠΈμ›Œν¬ μ—λŸ¬λ₯Ό λ²”μ£Όν™”ν•  λ•Œ μ‚¬μš©ν•˜λŠ” 였λ₯˜μ΄λ‹€.

μƒνƒœ μ½”λ“œ(status), 응닡 λ³Έλ¬Έ 일뢀(body), Content-Type(contentType)κ³Ό 같은 μΆ”κ°€ 메타λ₯Ό λ‹΄λŠ”λ‹€.

 

FetchErrorκ°€ μž‘λŠ” μ˜ˆμ‹œ μƒν™©μœΌλ‘œλŠ” μ•„λž˜μ™€ 같은 κ²½μš°λ“€μ΄ μžˆμ„ 것이닀.

  • λ°±μ—”λ“œ(μ™ΈλΆ€ API)μ—μ„œ 였λ₯˜ μƒνƒœ μ½”λ“œκ°€ 왔을 경우
    → 404 Not Found (μš”μ²­ 였λ₯˜)
     500 Internal Server Error (μ„œλ²„ 였λ₯˜)
    429 (μš”μ²­ κ³Όλ‹€)
  • 응닡 Content-Type이 μ˜ˆμƒν•œ ν˜•μ‹μ΄ 아닐 λ•Œ
    JSON ν˜•μ‹ 응닡을 κΈ°λŒ€ν–ˆλŠ”λ° text/html이 μ˜€λŠ” 였λ₯˜
βœ… HTML이 λ–¨μ–΄μ§€λŠ” 였λ₯˜
API μ„œλ²„μ— JSON을 μš”μ²­ν–ˆλŠ”λ°, λΉ„μ •μƒμ μœΌλ‘œ HTML λ¬Έμ„œ 응닡을 받을 μˆ˜λ„ μžˆλ‹€.
⋅ API μ„œλ²„ λ‚΄λΆ€ 였λ₯˜λ‘œ 500 Error Page(HTML)이 λ°˜ν™˜λ¨
⋅ 인증 μ‹€νŒ¨ μ‹œ 둜그인 νŽ˜μ΄μ§€(HTML)을 κ°•μ œλ‘œ λ¦¬λ‹€μ΄λ ‰νŠΈν•˜μ—¬ λ°˜ν™˜
⋅ nginx λ“± 쀑간 ν”„λ‘μ‹œ μ„œλ²„κ°€ HTML μ—λŸ¬ νŽ˜μ΄μ§€λ₯Ό λ°˜ν™˜

이런 경우 ν΄λΌμ΄μ–ΈνŠΈλŠ” μ•„λž˜μ™€ 같은 HTML을 받을 수 μžˆλ‹€.
<!DOCTYPE html>
<html>
  <body>500 Internal Server Error</body>
</html>

이럴 경우 res.json()을 μˆ˜ν–‰ν•˜λ©΄ νŒŒμ‹± 였λ₯˜κ°€ λ°œμƒν•  수 있고, Content-Type이 text/html둜, 잘λͺ»λœ μ‘λ‹΅μž„μ„ 확인할 수 μžˆλ‹€.

 

 

μ½”λ“œ

export class FetchError extends Error {
  public status?: number;
  public body?: string;
  public contentType?: string | null;
  constructor(message: string, opts?: { status?: number; body?: string; contentType?: string | null }) {
    super(message);
    this.name = 'FetchError';
    this.status = opts?.status;
    this.body = opts?.body;
    this.contentType = opts?.contentType ?? null;
  }
}
  • Error : Errorλ₯Ό 상속받아 ν‘œμ€€ μ—λŸ¬ κ΄€λ ¨ 00을 μ‚¬μš©ν•  수 μžˆλ‹€.
  • status, body, contentType : μΈμŠ€ν„΄μŠ€ ν•„λ“œλ₯Ό μ„ μ–Έν–ˆλ‹€. 
    응닡을 λ°›μ•„μ˜€λŠ” 도쀑 μ—λŸ¬κ°€ λ°œμƒν•œλ‹€λ©΄ 그건 μƒνƒœμ½”λ“œ, 응닡 λ³Έλ¬Έ, content typeμœΌλ‘œλΆ€ν„° μ™œ λ°œμƒν–ˆλŠ”μ§€ 확인할 수 있기 λ•Œλ¬Έμ— μ„Έ κ°€μ§€λ₯Ό μ„ μ–Έν–ˆλ‹€.
  • constructor(...) {... : μ—λŸ¬ μƒμ„±μžλ₯Ό μ •μ˜ν•œλ‹€.
    message : Error의 κΈ°λ³Έ λ©”μ„Έμ§€
    opts : μœ„μ—μ„œ μ •μ˜ν•œ μΈμŠ€ν„΄μŠ€
  • super(message) : λΆ€λͺ¨ 클래슀인 Error의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜μ—¬ message, μŠ€νƒ 트레이슀 λ“±μ˜ ν‘œμ€€ μ—λŸ¬ μ΄ˆκΈ°ν™”λ₯Ό ν•œλ‹€.
  • this.name : Error.name을 λͺ…μ‹œμ μœΌλ‘œ μ„€μ •ν•œλ‹€. λ‘œκΉ…/λΆ„κΈ°μ—μ„œ err.name으둜 μ—λŸ¬ νƒ€μž…μ„ νŒλ³„ν•  λ•Œ μ‚¬μš©ν•œλ‹€.
    μΆ”ν›„ handleError와 같은 μœ ν‹Έ ν•¨μˆ˜λ₯Ό μž‘μ„±ν•  λ•Œ (err instanceof FetchError)와 같은 μ‹μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.
  • this.status : optsκ°€ μžˆμ„ 경우 status 값을 ν• λ‹Ήν•˜κ³ , μ—†μœΌλ©΄ undefined둜 λ‚¨λŠ”λ‹€.
  • this.body : μ—λŸ¬ 응닡 본문을 ν• λ‹Ήν•œλ‹€. (디버깅, λͺ¨λ‹ˆν„°λ§μ— μ‚¬μš©ν•œλ‹€)
  • this.contentType : contentType을 ν• λ‹Ήν•˜λ˜, 없을 경우 null을 λͺ…μ‹œμ μœΌλ‘œ λ„£μ–΄ ν—€λ”κ°€ μ—†μŒμ„ ν‘œμ‹œν•œλ‹€.
βœ… JS 클래슀 문법 μƒμ„±μž
이 FetchErrorλΌλŠ” ν΄λž˜μŠ€κ°€ 처음 λ§Œλ“€μ–΄μ§ˆ λ•Œ ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜(즉, 초기 μ„ΈνŒ…μ„ ν•˜λŠ” ν•¨μˆ˜)κ°€ μƒμ„±μžμ΄λ‹€.
클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό μ΄ˆκΈ°ν™”ν•˜λŠ” 방식을 μ •μ˜ν•œλ‹€.
이 μƒμ„±μžλŠ” 인자둜 message, optsλ₯Ό λ°›μ•„μ„œ 초기 μ„ΈνŒ…μ„ μ§„ν–‰ν•œλ‹€.

* super() : λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜λŠ” κΈ°λŠ₯을 ν•œλ‹€. 
FetchErrorλŠ” Errorλ₯Ό μƒμ†ν•˜λ―€λ‘œ Error의 κΈ°λ³Έ κΈ°λŠ₯인 stack trace, message μ €μž₯ λ“±μ˜ Error μ΄ˆκΈ°ν™” 과정을 λ¨Όμ € μˆ˜ν–‰ν•œλ‹€.

* this : ν˜„μž¬ λ§Œλ“€κ³  μžˆλŠ” ν•΄λ‹Ή μ—λŸ¬ μΈμŠ€ν„΄μŠ€μΈ 자기 μžμ‹ μ„ 가리킨닀.
μƒˆλ‘œ μƒμ„±ν•œ 이 객체의 name, status, body, contentType을 μ§€μ •ν•˜λŠ” 것이닀.

 


3. TimeoutError : 응닡이 μ§€μ •λœ μ‹œκ°„ 내에 μ˜€μ§€ μ•Šμ•˜μ„ λ•Œμ˜ μ—λŸ¬

μš”μ²­μ΄ AbortController 등에 μ˜ν•΄ μ·¨μ†Œλ˜μ—ˆμ„ λ•Œ λ˜μ§€λŠ” 였λ₯˜μ΄λ‹€.

fetchλŠ” 기본적으둜 νƒ€μž„μ•„μ›ƒμ΄ μ—†κΈ°λ•Œλ¬Έμ— μ§€μ •ν•œ μ‹œκ°„ μ•ˆμ— 응닡을 λ°›μ§€ λͺ»ν•˜λ©΄ AbortController둜 κ°•μ œ μ’…λ£Œν•˜κ³ , κ·Έ λ•Œ λ°œμƒν•œ 였λ₯˜λ₯Ό μž‘λŠ” 것이닀.

βœ… AbortControllerλž€?
λΈŒλΌμš°μ €μ™€ Node ν™˜κ²½μ—μ„œ μ§€μ›λ˜λŠ” μš”μ²­ μ·¨μ†Œ API이닀.
fetch μš”μ²­μ— μ—°κ²°ν•˜λ©΄ AbortControllerκ°€ νŠΉμ • μ‹œμ μ— μš”μ²­μ„ κ°•μ œλ‘œ 쀑단할 수 μžˆλ‹€.
λŒ€ν‘œμ  μš©λ„λ‘œλŠ” μ•„λž˜μ™€ 같이 μžˆλ‹€.
⋅ νƒ€μž„μ•„μ›ƒ : 일정 μ‹œκ°„ λ‚΄ 응닡이 μ—†μœΌλ©΄ μš”μ²­ μ·¨μ†Œ
⋅ 쀑볡 μš”μ²­ μ·¨μ†Œ : 검색 μžλ™μ™„μ„±μ²˜λŸΌ 이전 μš”μ²­μ„ μ·¨μ†Œ
⋅ μ»΄ν¬λ„ŒνŠΈ μ–Έλ§ˆμš΄νŠΈ(cleanup) μ‹œ λ„€νŠΈμ›Œν¬ μš”μ²­ μ·¨μ†Œ

 

μ½”λ“œ

export class TimeoutError extends Error {
  constructor(message = 'Request timed out') {
    super(message);
    this.name = 'TimeoutError';
  }
}
  • constructor: μƒμ„±μžλŠ” λ©”μ„Έμ§€λ₯Ό μ„ νƒμ μœΌλ‘œ λ°›μœΌλ©°, 기본값은 'Request timed out'이닀.
  • super(message) : λΆ€λͺ¨μΈ Error의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•΄ message와 μŠ€νƒμ„ μ΄ˆκΈ°ν™”ν•œλ‹€.
  • this.name : name을 μ„€μ •ν•˜μ—¬ νƒ€μž… νŒλ³„μ„ μ‰½κ²Œ ν•˜λ„λ‘ ν•œλ‹€.
    instanceof κ²€μ‚¬λ‘œλ„ ν•΄λ‹Ή μ—λŸ¬κ°€ TimeoutErrorμž„μ„ ꡬ뢄할 수 μžˆλ‹€.
    예λ₯Ό λ“€μ–΄ μ•„λž˜μ™€ 같이 ν™œμš©ν•  수 μžˆλ‹€.
    if (err.name === 'TimeoutError')

 

 

 

 


4. ParseError : 응닡은 λ°›μ•˜μœΌλ‚˜, νŒŒμ‹± 쀑 λ°œμƒν•œ μ—λŸ¬

응닡을 μ •μƒμ μœΌλ‘œ λ°›μ•„μ™”μœΌλ‚˜, JSON으둜 νŒŒμ‹±ν•˜λŠ” λ‹¨κ³„μ—μ„œ μ‹€νŒ¨ν–ˆμ„ λ•Œ λ˜μ§€λŠ” 였λ₯˜μ΄λ‹€.

νŒŒμ‹± μ‹€νŒ¨ 원인 좔적을 μœ„ν•΄ 원본문 일뢀λ₯Ό 포함할 수 μžˆλ‹€.

  • JSON ν˜•μ‹μ΄ κΉ¨μ ΈμžˆλŠ” 경우
  • 응닡이 빈 λ¬Έμžμ—΄μΈ 경우
  • μ„œλ²„κ°€ 잘λͺ»λœ 포맷을 λ°˜ν™˜ν•œ 경우

 

export class ParseError extends Error {
  public raw?: string;
  constructor(message = 'Failed to parse response', raw?: string) {
    super(message);
    this.name = 'ParseError';
    this.raw = raw;
  }
}
  • public raw? : νŒŒμ‹± μ‹€νŒ¨ μ‹œ μ›μ‹œ 응닡 ν…μŠ€νŠΈλ₯Ό λ‹΄λŠ” ν•„λ“œλ‘œ, 디버깅을 μœ„ν•΄ μ •μ˜ν•œλ‹€.
  • κΈ°λ³Έ λ©”μ„Έμ§€λŠ” 'Failed to parse response'이며, λ‘λ²ˆμ§Έ 인자둜 μ›λ³Έλ¬Έμ˜ 일뢀λ₯Ό 받을 수 μžˆλ‹€.
  • super(message) : κΈ°λ³Έ Error μ΄ˆκΈ°ν™”λ₯Ό μˆ˜ν–‰ν•œλ‹€.
  • this.name : 'ParseError'둜 μ—λŸ¬ λ„€μž„μ„ μ„€μ •ν•΄ μ—λŸ¬ νŒλ³„ 및 λ‘œκΉ… ν‘œμ€€ν™”λ₯Ό λ•λŠ”λ‹€.
  • this.raw : 원본문을 μΈμŠ€ν„΄μŠ€μ— λ³΄κ΄€ν•˜μ—¬ ν˜ΈμΆœλΆ€κ°€ 상세 λ‚΄μš©μ„ 확인할 수 μžˆλ„λ‘ ν•œλ‹€.

 

 

 


5. λ…Έμ…˜ λ¬Έμ„œν™”

μž‘μ„±ν•΄λ³΄λ‹ˆ λ¬Έμ„œν™”λ₯Ό 해두면 μ’‹κ² λ‹€λŠ” 생각이 λ“€μ–΄, λ…Έμ…˜ νŽ˜μ΄μ§€λ₯Ό μƒμ„±ν•˜κ³  적어봀닀.

 

 

 

λ°˜μ‘ν˜•