Spring 정리ver2/Architecture

[Baedung] Best Practices for REST API Error Handling

태애니 2023. 4. 30. 18:48
728x90

 

링크의 포스팅 일자 2021.5.13

 

 

 

 

REST 는 Client가 서버의 resource에 access and manipulate 하는 stateless한 아키텍쳐이다

보통 REST service들은 HTTP를 활용한다

 

 

 

HTTP Status Codes

 

클라이언트가 HTTP 서버에 request하고 요청을 성공적으로 수신하면 서버는 해당 처리 여부를 response해준다

 

HTTP accomplishes this with five categories of status codes:

  • 100-level (Informational) – server acknowledges a request //서버가 요청을 승인했다
  • 200-level (Success) – server completed the request as expected // 예상대로 완료했다 (성공)
  • 300-level (Redirection) – client needs to perform further actions to complete the request // redirection
  • 400-level (Client error) – client sent an invalid request // client 의 잘못된 요청
  • 500-level (Server error) – server failed to fulfill a valid request due to an error with server // 개발한 내 잘못^^..

Based on the response code, a client can surmise the result of a particular request.

 

 

 

3. Handling Errors

 

3.1. Basic Responses

서버는 요류처리를 위해 client에게 적절한 상태코드로 response해주어야한다

 

일반적인 응답코드는 아래와 같다

 

  • 400 Bad Request – client sent an invalid request, such as lacking required request body or parameter
  • 401 Unauthorized – client failed to authenticate with the server
  • 403 Forbidden – client authenticated but does not have permission to access the requested resource
  • 404 Not Found – the requested resource does not exist
  • 412 Precondition Failed – one or more conditions in the request header fields evaluated to false
  • 500 Internal Server Error – a generic error occurred on the server
  • 503 Service Unavailable – the requested service is not available

이에 관련하여 세부 정보를 제공해야한다

 

그리고 500에러는 개발 한 내 잘못 서버 잘못이기 때문에 이 오류는내부적 오류이고 그에 맞게 응답처리를 해야한다

 

클라이언트로부터 발생된 오류 또한 최소화 시키기 위해 내부 오류를 처리하거나 포착한 뒤 다른 적절한 상태 코드로 응답해주어야한다.

 

요청한 리소스가 반환이 되지 않아 예외가 발생된 경우라면 500에러가 나겠지만 이를 404 에러로 표기하고 다른 처리를 할 수 있도록 돕거나 해당 이유를 안내해야한다. 

클라이언트가 사용하고 있는 서비스에 대한 중단 상황이 나타나지 않도록 해야한다.

 

 

3.2. Default Spring Error Responses

 

 

 

curl -X GET -H "Accept: application/json" http://localhost:8082/spring-rest/api/book/1

만약 Id가 1인 책의 정보가 없는데 클라이언트 쪽에서 요청을 했다면,

컨트롤러는 BookNotFoundException가 터질 것이다.

{
    "timestamp":"2019-09-16T22:14:45.624+0000",
    "status":500,
    "error":"Internal Server Error",
    "message":"No message available",
    "path":"/api/book/1"
}

기본 적인 spring error handler 에는 해당 오류가 생긴 시간 타임스탬프, 상태코드, 제목(오류필드), 기본 오류 메세지(기본적으로는 비어져있다) 등과 오류가 발생된 URL 경로를 알려준다.

 

이 필드의 내역 중에 클라이언트에게는 적절한 현재의 정보를 제공하거나, 개발자에게 문제 해결에 대한 정보를 받아 표준 오류 처리 메커니즘을 구성할 수 있도록 해야한다.

 

Spring은 BookNotFoundException 이 발생 하면 자동으로 HTTP 상태 코드 500을 반환하는데, 조금더 디테일 한 오류 코드를 구성하여 보여주는게 좋다.

 

이 때 그러한 오류를 통합적으로 관리할 수 있는 @ControllerAdvice를 추가하여  500 Internal Server Error 대신 Not Found를 나타내는 404 상태를 반환하도록 처리해줄 수 있다.

 

 

 

 

3.3. More Detailed Responses

StatusCode 만으로 오류 사항을 알리기에 충분하지 않을 수 있다. 이럴 때는 커스텀하여 client에게 추가 정보를 제공해줄 수 있다.

알려야하는 내용들은 아래와 같다

  • Error – a unique identifier for the error
  • Message – a brief human-readable message
  • Detail – a lengthier explanation of the error
{
    "error": "auth-0001",
    "message": "Incorrect username and password",
    "detail": "Ensure that the username and password included in the request are correct"
}

Error Field는 응답 코드와 일치하지 않는 각자 서버만의 고유 오류 코드를 처리한다. 보통은 위와 같은 방식의 규칙을 사용한다.

For example, 0001, auth-0001 and incorrect-user-pass are canonical examples of error codes.

 

Message portion of the body에는 일반적으로 사용자 인터페이스에서 보여줄 수 있는 것들이여야한다. 

Internationalization 를 지원하는 경우 각 국제화할 언어로 번역을 해두어야한다. 그리고 Accept-Language header와 함께 보여준다.

 

Detail portion 은 최종 사용자가 아닌 클라이언트 개발자가 사용하기 위한 내용들이다

 

또한 고객을 위한 help field URL 을 제공해줄 수 있다

{
    "error": "auth-0001",
    "message": "Incorrect username and password",
    "detail": "Ensure that the username and password included in the request are correct",
    "help": "https://example.com/help/error/auth-0001"
}

 

 

 

만약 request 에 대한 오류가 두개 이상이라면 list로 반환시켜줄 수 있다

{
    "errors": [
        {
            "error": "auth-0001",
            "message": "Incorrect username and password",
            "detail": "Ensure that the username and password included in the request are correct",
            "help": "https://example.com/help/error/auth-0001"
        },
        ...
    ]
}

단일 오류일 경우 하나의 요소를 포함하는 목록으로 응답한다

 

 

대부분은 첫번째, 또는 가장 중요한 오류로 응답하는게 좋다

 

 

3.4. Standardized Response Bodies

대부분의 REST API는 유사한 규칙을 따르지만 필드 이름 및 응답 본문에 포함된 정보를 포함하여 세부 사항은 일반적으로 다양하다.

이러한 차이로 인해 라이브러리와 프레임워크가 오류를 균일하게 처리하기가 어렵다.

 

REST API 오류 처리를 표준화하기 위한 노력의 일환으로 IETF는 일반화된 오류 처리 스키마를 생성하는 RFC 7807 이 있다

 

RFC 7807: Problem Details for HTTP APIs

 

www.rfc-editor.org

 

이 스키마는 다섯 부분으로 구성되어있다

 

  1. type – a URI identifier that categorizes the error //오류 분류 URI
  2. title – a brief, human-readable message about the error // 오류에 대해 알려주는 메세지
  3. status – the HTTP response code (optional) // HTTP 응답코드
  4. detail – a human-readable explanation of the error // 오류 설명
  5. instance – a URI that identifies the specific occurrence of the error //특정 오류 발생을 식별하는 URI

사용자 지정 오류 응답 본문을 사용하는 대신 본문을 변환할 수 있다.

{
    "type": "/errors/incorrect-user-pass",
    "title": "Incorrect username or password.",
    "status": 401,
    "detail": "Authentication failed due to incorrect username or password.",
    "instance": "/login/log/abc123"
}

유형 필드는 오류 유형을 분류하는 반면 인스턴스는 각각 클래스 및 개체와 유사한 방식으로 특정 오류 발생을 식별한다.

 

URI를 사용하여 클라이언트는 HATEOAS 링크를 사용하여 REST API를 탐색하는 것과 같은 방식으로 이러한 경로를 따라 오류에 대한 자세한 정보를 찾을 수 있다.

RFC 7807 준수는 선택 사항이지만 균일성을 원하는 경우 유리하다고 한다

 

 

 

 

 

 

(예시는 생략)

728x90