티스토리 뷰
API 만들때 에러 메세지 정책을 어떻게 해주는 게 좋을까?! 를 많이 고민했습니다.
(장고로 API 개발 + 플러터로 클라이언트 개발을 동시에 하고 있어가지구 이 정책에 따라 클라도 같이 바꿔해서,,,😶)
그래서 고민한 것들을 기록해두려고 합니다.
우선 크게보면 사용자가 얼럿으로 만나게 되는 에러메세지를
서버에서 결정할 것인지, 클라이언트에서 결정할 것인지 정해야하는 문제인데요
더 구체적으로 생각해보면
<클라에서 결정>
후보1)
서버: api에서 status code만 내려준다.
클라: api에서 내려주는 status code를 보고 클라이언트에서 에러메시지를 매핑한다.
후보 2)
서버: api에서 status code 뿐만아니라 개발자가 이해할 수 있는 에러메세지를 내려준다.
(예를들어, header값이 올바르지 않습니다.)
클라: api에서 내려주는 status code를 보고 클라이언트에서 에러메시지를 매핑한다.
<서버에서 결정>
후보 1)
서버: api에서 사용자가 이해할 수 있는 에러메세지를 내려준다.
(header값, 유효하지 않은 토큰... 이런말 쓰면 안되고 일반 사용자가 이해할 수 있는 에러 메세지)
클라: api에서 받은 것을 그대로 보여준다.
후보 2)
서버: api에서 사용자, 개발자가 이해할 수 있는 에러메세지를 각각 내려준다. (화면용 / 디버깅용 에러메세지가 따로 있음)
클라: api에서 받은 것을 그대로 보여준다.
그럼 각 후보들의 장단점들을 살펴보겠습니다. (지극히 서버는 장고입장입니다)
[1] 클라에서 결정
1.1 장고 입장
장점
장고에서는 이렇게 try, except 해줘야하는 대신
한줄로 object를 못가져오면 404 에러를 내려주는 shortcut 메소드가 있습니다.
근데 get_object_or_404 메소드에는 커스텀 에러메세지를 지정해줄 수 없어요...!
(만약 지정해주려면 github.com/django/django/blob/master/django/shortcuts.py 여기서 구현을 보고 따로 메소드를 만들어야할까나요..? 저는 안해봤습니다.)
아무튼 get_object_or_404, get_list_or_404 같은 shortcut 메소드를 마음껏 쓸 수 있다는 점이 장점입니다.
(만약 에러메세지를 내려줘야하면 이거 못쓰고 try, except해야하니까..!)
한줄로 쓰게 되면 편할뿐만아니라 코드 가독성도 확 높아지거든요..!
그리고 custom exceptionHandler을 만들어서 에러응답을 커스터마이징 하자 같은 방법이 있긴한데
이건 전역적으로(?) status code에 따른 에러메세지를 정해줄 수 있는 방법이라서
각 api 마다 status code가 같은데 다른 에러메세지를 내려주고 싶다!! 하면 못쓰는 방법입니다.
단점
딱히 없는 듯 합니다.
1.2 클라이언트 입장
장점
클라이언트가 얼럿을 띄우는 주체인데 클라에서 마음대로 에러메세지를 설정해줄 수 있어서 좋습니다.
단점
서비스가 많아지면 statusCode에 따라 에러메세지를 매핑해주는 코드도 같이 많아집니다.
예를들어 회원가입 api를 콜하고 status code에 따라 error 종류를 매핑하주는 코드인데요
api를 부르는 서비스가 많아지면 error 매핑도 같이 많이 해줘야하니까 귀찮습니다.
그리고 api에서 status code를 바꾸거나 추가하는 등 하면
클라도 같이 수정해줘야한다는 점도 단점입니다.
1.3 두 후보간 차이..?
이렇게 두가지 후보가 있었는데,
사실 장고에서는 큰 차이가 없습니다.
클라 개발자가 볼 것이기 때문에 장고에서 기본적으로 내려주는 에러 메세지를 보내도 상관없습니다.
아래는 장고에서 기본적으로 주는 에러메세지인데 클라 개발자도 충분히 이해가능한 메세지입니다.
위에서 말한 get_object_or_404 역시 마음껏 써도 됩니다.
그리고 아래 예제처럼 같은 status code라도 api에서 에러메세지를 구체적으로 쪼개준다면
클라이언트에서 디버깅하기 더 쉬울 것 같아요-!!
[2] 서버에서 결정
2.1 장고 입장
장점
클라에서 status code에 따라 올바른 에러메세지를 잘 매핑하도록 문서에 부연설명(?)을 안해도 된다...(??)
(문서화를 안해도 된다는 뜻은 아니고 간단히 해도 된다는 의미,,,?)
단점
위에서 말한 shortcut 함수들을 맘놓고 쓸 수 없다.
책임감을 가지고(??) 사용자에게 보일 에러메세지 처리를 확실하게 해줘야함.
2.2 클라 입장
장점
서버에서 준 메세지 그대로 보여주면 되니까 편하다. 서버에서 수정사항있어도 클라가 같이 바꿔줘야하는 일 없다.
단점
어떻게 생각하면 장점이 단점이 될수도,,, 내가 얼럿띄우니까 얼럿 메세지는 내가 정할꺼야,, 하고 싶을 수도 있다.
2.3 두 후보간 차이..?
이렇게 두 후보가 있었습니다.
후보 2번은 사실 필드하나 더 추가하는 것인데
굳이 이렇게까지 안해도 될 것 같아요 (이렇게 까지 안해도 클라개발자가 디버깅 충분히 잘할 수 있을 것이라 생각합니다.)
[3] 저의 선택은..
저는 서버개발자도, 클라개발자도 저이기 때문에
가장 리소스가 적게 들어가는 이 방법으로 결정했습니다.
<서버에서 결정>
후보 1)
서버: api에서 사용자가 이해할 수 있는 에러메세지를 내려준다.
(header값, 유효하지 않은 토큰... 이런말 쓰면 안되고 일반 사용자가 이해할 수 있는 에러 메세지)
클라: api에서 받은 것을 그대로 보여준다.
그리고
custom exceptionHandler 랑 기본 exception 을 같이 사용해서 에러메세지 대응을 해줬습니다.
장고에서 기본적으로 설정되어있는 에러메세지는 custom exceptionHanlder로 대응
& 그외에 제가 일으키는 에러메세지는 exception으로 대응했습니다.
예를들어 header에 Autorization이 없다면
제가 exception을 일으키는데 여기 에러메세지를 지정해줬구요
request.user 코드가 실행될때
Authorization 헤더값으로 유효하지 않은 토큰이 들어왔다면
장고에서 아래 처럼 에러메세지를 줍니다.
근데 저 기본 메세지가 사용자에게 보이면 좀 그러니까
custom_exception_handler에서 에러메세지를 바꿔주었습니다.
그리고 get_object_404도
만약 값을 못찾으면 이런 기본 에러메시지를 내려주게 되어있는데
이렇게 사용자에게 보여주기 좀 그러니까
커스텀 에러메시지를 설정해줬습니다.
'🐍 > DRF' 카테고리의 다른 글
[DRF] 쿼리스트링을 받을 수 있는 URL 만들기 (2) | 2020.10.06 |
---|---|
[DRF] custom exceptionHandler을 만들어서 에러응답을 커스터마이징 하자 (0) | 2020.09.30 |
[DRF] SerializerMethodField로 모델에서 변형된 JSON을 내려주기 (0) | 2020.09.26 |
[DRF] 기본 Exception과 APIExecption (0) | 2020.09.24 |
[DRF] TokenAuthentication (유저마다 토큰을 발급해서 유저를 식별해보자) (10) | 2020.09.21 |
- Total
- Today
- Yesterday
- 장고 Custom Management Command
- Django Firebase Cloud Messaging
- github actions
- flutter deep link
- Flutter Clipboard
- Dart Factory
- 플러터 싱글톤
- Watch App for iOS App vs Watch App
- Flutter 로딩
- METAL
- 장고 URL querystring
- Flutter getter setter
- flutter dynamic link
- flutter 앱 출시
- ribs
- cocoapod
- Django Heroku Scheduler
- PencilKit
- Flutter Text Gradient
- ipad multitasking
- Sketch 누끼
- drf custom error
- Django FCM
- 구글 Geocoding API
- DRF APIException
- Python Type Hint
- flutter build mode
- SerializerMethodField
- Flutter Spacer
- 플러터 얼럿
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |