python/Django
ValidationError – API/Form 검증
Balang
2025. 4. 28. 14:07
728x90
API 개발하면서, Form이나 API Serializer를 통해 입력 값을 검증해야합니다.
근데 사용자가 잘못된 데이터를 보내거나, 빠뜨리거나, 이상한 형식으로 보내면 ValidationError가 발생합니다.
rest_framework.exceptions.ValidationError:
문제는, 서버에서 ValidationError를 제대로 잡지 않으면 500에러가 발생하고,
API 클라이언트(앱/프론트앤드)에서는 "서버 오류" 처럼 오해할 수 있습니다.
→ 사용자 탓인데 서버 오류처럼 보이게 되는 셈이죠.
원인 분석
- Django Form, ModelForm, DRF Serializer 모두 내장 검증(validation) 기능을 가지고 있습니다.
이 검증 과정에서 문제가 발생하면 ValidationError 예외가 발생합니다.
이 예외를 적절히 처리하지 않으면, Django는 그냥 500 에러를 반환해버립니다.
즉, 사용자의 입력 오류가 서버 내부 오류(500) 처럼 보이는 것이죠.
해결 방법
- Form/ Serializer의 is_valid()를 반드시 검사
- form.is_valid() , serializer.is_valid() 호출 후 예외처리
- ValidationError를 try-except로 명시적으로 핸들링
- ValidationError를 캐치해서 클라이언트에 400 Bad Request로 응답
- 에러 메세지를 깔끔하게 정리해서 보내기
- 검증 실패 시 어느 필드가, 어떤 이유로 실패 했는지 반환
- API 레벨에서는 400 (Bad Request)로 처리
- 절대 서버 500이 아니라 요청 오류로 분리해야 한다.
Django Form 기반 View 예시
from django.http import JsonResponse
from django.views import View
from .forms import SignupForm
from django.core.exceptions import ValidationError
class SignupView(View):
def post(self, request):
form = SignupForm(request.POST)
if form.is_valid():
# 정상 처리
user = form.save()
return JsonResponse({'message': '가입 성공'}, status=201)
else:
# 입력 오류 처리
return JsonResponse({'errors': form.errors}, status=400)
DRF Serializer 기반 API 예시
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializers import SignupSerializer
from rest_framework.exceptions import ValidationError
class SignupAPIView(APIView):
def post(self, request):
serializer = SignupSerializer(data=request.data)
try:
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({'message': '가입 성공'}, status=status.HTTP_201_CREATED)
except ValidationError as e:
return Response({'errors': e.detail}, status=status.HTTP_400_BAD_REQUEST)
"""
DRF에서는 raise_exception=True 옵션을 주면 알아서 400 오류로 변환해준다.
e.detail은 필드별 에러를 dict 형태로 꺼낼 수 있다.
"""
ValidationError를 커스텀 핸들링
"""
공통 예외 처리로 ValidationError를 관리하고 싶을 때는,
Django의 middleware 또는 DRF의 exception handler를 이용할 수 있다.
"""
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if isinstance(exc, ValidationError):
# ValidationError는 400 응답
response.data = {
'success': False,
'errors': response.data
}
return response
# setting.py
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'myproject.exceptions.custom_exception_handler'
}
위에서도 말했지만 ValidationError는 사용자 입력 오류이지, 서버 오류가 아닙니다.
올바른 HTTP 상태코드(400)를 보내야 API UX가 좋아집니다.
정확한 필드별 오류를 알려주면 프론트엔드나 앱 개발자도 훨씬 편해집니다.
보안 측면에서도 통제된 오류 메세지만 노출할 수 있습니다.
단, 여기서 주의할 점이
- form.errors, serializer.errors는 dict 형태입니다.
- 바로 JSON으로 반환할 수 있습니다.
- API 응답 포맷을 통일하는게 좋습니다.
- 예를 들어 항상 {success: False, errors: {error_message}}
정리
Django에서 ValidationError를 만났다면, 사용자 입력 오류로 분류하고,
반드시 400 Bad Request로 클라이언트에 명확한 오류 메세지를 반환해야 한다.
728x90
반응형