drf エラーハンドリング
リソースに変更を加えるapiを作る際に、以下の要望があった。 apiを叩いたら成功したか失敗したかの結果をTrue, Falseで欲しい。この場合drfでResponseオブジェクトを返せば良い。
return Response({"success":True}) # または return Response({"success":False})
こんな感じで返せば良い。こうするとフロントエンドでsuccessの結果から処理を分岐させることができるようになり、統一するとフロントエンド側が書きやすくなる。
これを実装するにはエラーハンドリングについて少し考える必要があり、それに関する良い記事がある。
関連するソースコードはこちら:
django-rest-framework/exceptions.py at master · encode/django-rest-framework · GitHub
具体例な解決案
クライアントの操作に誤りがある場合には、djangoが自動的にエラーをすくいとり、エラーがあった旨のレスポンスを自動的に返す。それを使っている以上responseにはsuccessキーは使えない。
エラーをキャッチしてなおかつsuccessキーを返すには以下のようにすると良い。 一言添えるならば、drf上ではエラーが発生したらexception_handlerが呼び出され、handle_exceptionが作動する。こいつがdrfのエラーをどう処理するか定めているものなので、そこを自分好みにカスタマイしてみてはどうか?ってことだ。
from rest_framework.views import APIView from rest_framework.exceptions import APIException, NotFound class BookTagView(APIView): def get_exception_handler(self): default_handler = super().get_exception_handler() def handle_exception(exc, context): if isinstance(exc, KeyError): return Response({'success': False, 'error': { 'message': exc.detail, } }, status_code=exc.status_code) elif isinstance(exc, NotFound): return Response({'success': False, 'error': { 'message': exc.detail, } }, status_code=exc.status_code) else: # unknown exception return default_handler(exc, context) return handle_exception def post(self, request): data = request.data try: book_title = data["book_title"] tag = data['tag'] except KeyError: raise KeyError() try: book = Book.objects.get(title=book_title) except NotFound: raise NotFound() book.tags.add(tag) book.save() return Response({"success": True}) class KeyError(APIException): status_code = status.HTTP_400_BAD_REQUEST default_detail = _('送信データのkeyにはbook_title, tagがないのでエラーとなります') default_code = 'key_error'