v2_exceptionhandling - 100-hours-a-week/KTB4-8th-BE GitHub Wiki

μ˜ˆμ™Έ 처리

ν˜„μž¬ 이 μ„œλΉ„μŠ€μ—μ„œ λ°œμƒν•  수 μžˆλŠ” μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

  • μ‹œνλ¦¬ν‹° 계측

401 μš”μ²­μ˜ 인증 μ—¬λΆ€: AT 검증 μ‹€νŒ¨, RT 검증 μ‹€νŒ¨, ...?

403 μš”μ²­μ˜ 인가 μ—¬λΆ€: 일단 v2κΉŒμ§€ λ°œμƒν•  일 μ§„μ§œ 거의 μ—†μŒ.

  • 컨트둀러 계측

400 μš”μ²­μ˜ μ˜¨μ „μ„±?: λŒ€λΆ€λΆ„ μ •ν•΄μ Έ 있으며, μ™ΈλΆ€λ‘œλŠ” ꡳ이 μ„ΈλΆ€μ μœΌλ‘œ λ‚˜λˆŒ 이유 μ—†μŒ. 둜그만 μž˜ν•˜μž

405 μš”μ²­ λ©”μ†Œλ“œμ˜ 지원 μ—¬λΆ€: YES or NO만이 μ€‘μš”ν•˜λ‹€. λ‚˜λˆŒ ν•„μš” μ—†

422 μš”μ²­ ν•„λ“œκ°€ 검증 κ²°κ³Ό μœ νš¨ν•œ 값을 κ°€μ‘ŒλŠ”μ§€: λ‚˜λˆ μ•Ό 됨...

413 μš”μ²­ 본문의 파일 ν˜•μ‹μ„ μ§€μ›ν•˜λŠ” μ§€: YES or NO만이 μ€‘μš”ν•˜λ‹€. λ‚˜λˆŒ ν•„μš” μ—†

415 μš”μ²­ 본문의 파일이 μ œν•œ λ²”μœ„ 이내인지: YES or NO만이 μ€‘μš”ν•˜λ‹€. λ‚˜λˆŒ ν•„μš” μ—†

429 μš”μ²­μ΄ Rate Limit을 λ„˜μ§€ μ•Šμ•˜λŠ”μ§€: YES or NO만이 μ€‘μš”ν•˜λ‹€. λ‚˜λˆŒ ν•„μš” μ—†

  • μ„œλΉ„μŠ€ 계측

404 λ¦¬μ†ŒμŠ€μ˜ μ‘΄μž¬μ„±: λ‚˜λˆ μ•Ό 됨

409 μš”μ²­μ˜ λ‚΄μš©κ³Ό μ„œλ²„μ˜ μƒνƒœκ°€ μΆ©λŒν•˜λŠ” μ§€: λ‚˜λˆ μ•Ό 됨

500 μ„œλ²„ 였λ₯˜: 이것도 λ‚΄λΆ€ λ‘œκΉ…μ€ μž˜ν•΄μ•Ό 함

502 μ™ΈλΆ€ API 였λ₯˜ (κ·Έ μ™Έ)

503 λ‚΄λΆ€ API 였λ₯˜ (AI μ„œλ²„)

μ˜ˆμ™Έ 클래슀 ꡬ쑰 ꡬ성 (+ messageSource μ—°κ²°)

base class

messageSource κ΄€λ ¨ μ„€μ •

2단계

HTTP μƒνƒœ μ½”λ“œλ³„ λΆ„κΈ° 적용, κΈ°λ³Έ λ©”μ„Έμ§€ μž‘μ„±, μƒνƒœ μ½”λ“œ 별 ProblemDetail ν˜•μ‹ μ •μ˜

κΈ°λ³Έ ν˜•μ‹

{
  "trace_id": String,
  "code": String,
  "type": URI,
  "title": String,
  "instance": URI,
}

3단계

μƒνƒœ μ½”λ“œμ—μ„œ 더 μ„ΈλΆ€μ μœΌλ‘œ λΆ„κΈ°κ°€ ν•„μš”ν•œ λ³Έλ¬Έλ“€

  • 401, 404, 409, 502?λŠ” μ„ΈλΆ€μ μœΌλ‘œ λ‚˜λˆŒ ν•„μš”κ°€ 있음

422

{
  "trace_id": String,
  "code": String,
  "type": URI,
  "title": String,
  "instance": URI,
  "errors": [
    {
      "code": "String",
      "detail": String,
      "pointer": JSON Pointer
    },
    ...
  ]
}
  1. @Valid @RequestBody 단독 -> MethodArgumentNotValidException (λ©”μ†Œλ“œ νŒŒλΌλ―Έν„°μ— λŒ€ν•œ 직접적인 μœ νš¨μ„± 검증이 λ°œμƒν•˜μ§€ μ•Šμ•˜μ„ 경우)
  2. λ‚˜λ¨Έμ§€ (μ–΄λ– ν•œ 경우던 간에 @NotNull, @Positive λ“± λ©”μ†Œλ“œ νŒŒλΌλ―Έν„°μ— μœ νš¨μ„± 검증 μ–΄λ…Έν…Œμ΄μ…˜μ— μ˜ν•œ 직접적인 μœ νš¨μ„± 검증이 λ°œμƒν•œ 경우) -> HandlerMethodValidationException
  • 흐름

    1. HandlerMethodValidationException

      • HandlerMethodValidationException.getParameterValidationResults().methodParameter.parameterName(본문이 μ•„λ‹Œ 경우 = result.type = ParameterValidationResult) λ˜λŠ” HandlerMethodValidationException.getParameterValidationResults().fieldErrors.field(본문인 경우 = result.type = ParameterErrors)μ—μ„œ ν•„λ“œ 이름을 μΆ”μΆœν•΄ 였λ₯˜ μ½”λ“œλ₯Ό λ§€ν•‘ -> code, detail, pointer

      • νŒŒλΌλ―Έν„° μœ νš¨μ„± κ²€μ¦μš© messageSource에 각 μ½”λ“œλ³„ detail ν•„μš”

        • 이 λˆ„λ½μ„ 컴파일 μ˜ˆμ™Έλ‘œ μ˜ˆλ°©ν•œλ‹€λ©΄?
        • pointerλŠ” fieldκ°€ 전체 경둜λ₯Ό κ°€μ§€κΈ° λ•Œλ¬Έμ—, κ·ΈλŒ€λ‘œ μ“°κ±°λ‚˜ 쑰금 λ³€ν˜•ν•˜λ©΄ 될듯
      • FieldErrorsμ—μ„œλŠ” fieldκ°€ 전체 경둜λ₯Ό κ°€μ§€κΈ° λ•Œλ¬Έμ—, λ§€ν•‘ μ‹œ split(".") λ“±μœΌλ‘œ μŠ¬λΌμ΄μ‹±μ΄ ν•„μš”ν•  λ“―

    2. MethodArgumentNotValidException

      • getFieldErrors둜 ν•„λ“œλ³„ 였λ₯˜μ— μ ‘κ·Όν•  수 μžˆλ‹€κ³  함
  • κ΅¬ν˜„

    • @RestControllerAdvice

      • @ExceptionHandling(HandlerMethodValidationException.class), @ExceptionHandling(MethodArgumentNotValidException.class)
      • ν•„λ“œ 이름과 였λ₯˜ μ½”λ“œλ₯Ό λ§€ν•‘
      • FieldErrors의 각 ν•„λ“œ 였λ₯˜λ₯Ό code, detail, pointerλ₯Ό κ°€μ§„ DTO둜 λ§€ν•‘ν•˜μ—¬ errors μ»¬λ ‰μ…˜μœΌλ‘œ λ³€ν™˜
      • errorsλ₯Ό 담은 422 였λ₯˜λ‘œ λ³€ν™˜
    • message.properties

      • 였λ₯˜ μ½”λ“œμ— λŒ€μ‘ν•˜λŠ” detail μž‘μ„±

TO-BE

3단계 μ˜ˆμ™Έ

μ˜ˆμ™Έ 클래슀: 2단계 μ˜ˆμ™Έ extend, μ˜ˆμ™Έ 별 code μ„ μ–Έ

message.properties: 였λ₯˜μ˜ type, title만 μ„ μ–Έ

2단계 μ˜ˆμ™Έ

각 μƒνƒœ μ½”λ“œ 별 fallback용 code, type, title μ„ μ–Έ

base class

codeλ₯Ό μ΄μš©ν•΄ message.propertiesμ—μ„œ 였λ₯˜μ— ν•΄λ‹Ήν•˜λŠ” type, title 쑰회, ProblemDetail 생성

  • getTypeMessageCode(), getTitleMessageCode()
new ErrorResponseException(status, body, cause, messageDetailCode, null)