에러코드가 필요한 이유
개발 단계에서 서버에 요청을 보냈을 때 서버에서 “Oops, something went wrong” 따위의 오류 메시지를 반환한다면 Client의 문제인지 Server의 문제인지 알 기 어렵다. 따라서 Server 는 Client의 요청에 대해 구체적인 에러 메시지를 전달해 줄 필요가 있다.
장점
- HTTP Status code 만으로 Response에 대한 충분한 설명을 할 수 없다.
- 더욱 구체적인 에러 내용을 정의하여 소통할 수 있다.
- 오류 메시지는 API 사용 방법에 대한 가시성을 제공하는 핵심 도구가 된다.
- 클라이언트단에서 에러 코드에 따라 다른 처리 로직을 개발할 수 있다.
- HTTP status code만으로 모든 예외처리를 할 수 없다.
- 따라서 status code와 응답의 message를 추가로 참조하여 로직을 개발해야한다.
- message 에 종속되는 것보다 내부 error code에 종속되는 것이 낫다
- 클라이언트단의 코드가 더 변화가능성이 적은 부분에 종속되게 함
좋은 어플리케이션 에러 핸들링 디자인
Application Level 에러코드는 정확한 표준이 없어 어플리케이션마다 구조가 상이하다. 다음과 같은 내용을 고민해보는 것은 좀 더 나은 에러코드 구조를 만드는 것을 도와줄 것이다.
- 어떤 HTTP status code 들을 사용해야하는가
에러상황에 맞는 HTTP status code를 반환하는 것이 우선이다.
HTTP status code는 70개가 넘게 세분화되어 있지만, 대부분의 개발자가 모든 code를 암기하지 않을 뿐더러 잘 사용되지 않는 code를 사용하는 것은 개발에 추가적인 비용을 발생시킬 수 있다. 프로그램이 크지 않다면 HTTP status code를 일부만 사용하고 자세한 내용은 Response Body 에 담는 것이 좋다.
HTTP status code는 다음과 같이 3개의 코드로만 한정할 수도 있다.
- 정상적 요청 및 정상적 응답(200)
- Client 측 오류(404)
- Server 오류(500)
만약 이 단계에서 API에 대해 좀 더 세분화한 코드가 필요하다고 생각되는 경우 새로운 status code를 도입할 수 있다. 너무 적은 status code는 관심사가 다른 application level error 가 같은 status code로 취급될 수 있고, 너무 많은 status code는 개발에 비용을 증가시킬 수 있다. 따라서 프로그램에 적합한 수준의 status code 개수를 선택해야 한다. Google GData API 는 10개, Netflix 는 9개, Digg는 8개의 code만을 사용한다.
- 어떤 내용을 담아야하는가
크게 세 가지로 나눌 수 있다.
- Error Code : 오류에 대한 식별자. 오류 코드
- Message : 오류 코드에 대한 설명. Human-readable
- Detail : 오류에 대한 자세한 설명 및 메타데이터
Error Code
Error Code는 integer 일 수도 string 일 수도 있다.
예)
code: 1001 (숫자 방식)
code: INVALID_REQUEST (문자열 방식)
code: “AUTH-001” (문자열 방식2: 문자와 숫자 혼용)
숫자 방식은 코드만으로 에러의 내용을 파악하기 어렵다는 단점이 있지만, 컴퓨팅적 자원을 더 적게 소모할 수 있게 한다. 반대로 문자열 방식은 코드를 통해 에러의 내용을 유추할 수 있지만, 컴퓨팅적 연산에 있어 더 큰 자원을 소모한다.
에러 코드는 HTTP status code 와 구분되는 것을 방지하기 위해 음수로 작성할 수도 있다.
에러 코드에 계층을 부여하여 Code - SubCode 와 같이 운용할 수도 있다.
예)
{ “code”:300 , “subcode”:”001” }
Message
Message는 오류에 대해 간략하게 설명하는 사람이 읽을수 있는 글이다. 이 메시지는 일반적으로 사용자 인터페이스에 표시 될 수 있는 것으로 간주되므로, 만약 국제화를 지원하는 어플리케이션이라면 언어에 따라 다른 메시지를 반환할 수 있어야 한다.
개발자에게 전하는 메시지와 End-User에게 전하는 메시지를 나누기 위하여 message-dev, message-end-user 와 같이 분리하여 사용할 수도 있다.
Detail
Detail 에 포함될 수 있는 요소의 예로는 다음과 같은 것들이 있다.
- errorDetail: 오류에 대한 자세한 설명
- tip : 오류를 해결하기 위한 방법
- reference : 해당 오류의 api 문서 주소
- address : 오류가 발생한 URI
- trace_id : 오류가 발생한 부분의 로그 id
- version : API 버전
- 기타등등
Detail 은 자유롭게 작성하면 된다.
반면 너무 많은 정보의 제공은 클라이언트-서버의 부하를 늘릴 뿐 더러, 개발자가 응답을 분석하고 이해하기에 어려워 디버깅에 문제가 생길 수 있다. 따라서 간결하게 필요한 정보만 담아 전달하는 것이 중요하다.
- Error Code 설정 전략
어떤 오류에 어떤 숫자를 매칭하는지는 중요한 부분으로 생각없이 오류 코드를 할당한다면 나중에 엉망진창이 된 오류 코드 목록을 확인할 수 있다. 이것을 방지하기 위해 오류 코드 범위를 정의할 필요가 있다.
example Error code (숫자방식)
- 공통적인 오류 (general errors) for 1 to 100
- 리소스별 오류
- /users 이하에서 생기는 오류 for 101 to 200
- /items 이하에서 생기는 오류 for 201 to 300
서로 다른 리소스에서 발생하는 오류의 개수가 다를 수 있으므로 서로 다른 리소스에 서로 다른 범위 크기를 할당할 필요가 있다. 이 범위의 크기를 추정하는 것 역시 API를 설계할 때 고려해야하는 사항이다.
다음과 같이 리소스의 이름을 Error Code에 넣을 수도 있다.
- 공통 오류
- general-001 ~ general-999
- 리소스별 오류
- resource-001 ~ resource-999
이 경우 리소스 이후에 나오는 숫자가 통일되게 사용한다면 좀 더 구조적인 접근을 할 수 있게 된다.\
예)
resource-001 ~ 015 : resource 생성시 발생하는 오류
resource-016 ~ 030 : resource 수정시 발생하는 오류
…
예시
IETF 표준
- REST API의 에러 핸들링의 표준화를 위해서 RFC 7807에서 제시한 에러핸들링 일반 구조.
- 총 5개의 필드로 구성
- type : 세부 에러 코드
- title : 에러에 대한 간략한 설명
- status(optional) : HTTP response code
- detail : 에러에 대한 자세한 설명
- instance : 에러 발생 근원지 URI
- 예시
{
"type":10001,
"title":"Incorret username or password",
"detail":"Authentication failed due to incorrect username or password.",
"instance":"/api/login"
}
관련 도큐먼트 Link 포함 방식
- 에러 코드 번호와 해당 에러 코드 번호에 대한 Error dictionary link를 제공하는 방법
- error 문서의 관리가 요구됨
- 예시
{
"status":401,
"message":"Authenticate",
"code":"HY10001",
"more info":"https://www.domain.com/docs/authenticate/hy10001"
}
Trace id 포함 방식
- 어플리케이션에서 로깅에 사용한 trace id를 반환하여 추후에 쉽게 확인할 수 있게 한다.
- 직접적인 에러 정보를 노출하지 않기 때문에 보안에 유리하다.
- 예시
{
"message": "Missing redirect_uri parameter.",
"type": "OAuthException",
"code": 191,
"fbtrace_id": "AWswcVwbcqfgrSgjG80MtqJ"
}
Uploaded by N2T