API 서버는 항상 다양한 요청을 받는다.
그 중에는 잘못된 요청도 있고, 권한이 없는 사용자 요청도 있고, 시스템 내부에서 예기치 않게 터지는 오류도 있다.
에러 처리는 단순히 "오류를 잡는 것"이 아니라, 사용자에게 문제의 원인을 명확히 전달하고, 시스템 상태를 안전하게 유지하는 행위다.
"필수 필드가 누락되었습니다"
처럼 사용자 친화적 피드백 가능Lambda에서 API Gateway를 통해 호출되는 함수는 다음 구조로 응답을 반환해야 한다:
{
"statusCode": 200,
"body": "{\"message\": \"hello\"}",
"headers": {
"Content-Type": "application/json"
}
}
statusCode
: HTTP 상태 코드body
: 문자열 형태의 JSONheaders
: JSON 형식임을 명시주의: body
는 JSON 객체가 아니라, 문자열(stringified JSON) 이어야 함
상태 코드 | 의미 | 언제 쓰는가? |
---|---|---|
200 OK | 정상 응답 | 요청 처리 성공 시 |
400 Bad Request | 잘못된 요청 | 필수 파라미터 누락, 타입 오류 등 |
401 Unauthorized | 인증 실패 | 로그인 또는 토큰 누락 시 |
403 Forbidden | 권한 없음 | 유효한 유저지만 접근 권한이 없음 |
404 Not Found | 리소스 없음 | 없는 ID로 조회할 때 등 |
422 Unprocessable Entity | 요청 구조는 맞지만 의미상 문제 | 유효하지 않은 값이 들어왔을 때 |
500 Internal Server Error | 시스템 내부 오류 | 예기치 않은 예외 발생 시 |
from http import HTTPStatus
from aws_lambda_powertools.logging import Logger
import json
logger = Logger()
def handler(event, context):
try:
name = event.get("queryStringParameters", {}).get("name")
if not name:
return {
"statusCode": HTTPStatus.BAD_REQUEST,
"body": json.dumps({"message": "Missing required parameter: name"})
}
return {
"statusCode": HTTPStatus.OK,
"body": json.dumps({"message": f"Hello, {name}!"})
}
except ValueError as ve:
logger.warning(f"Validation failed: {ve}")
return {
"statusCode": HTTPStatus.UNPROCESSABLE_ENTITY,
"body": json.dumps({"message": str(ve)})
}
except Exception as e:
logger.exception("Unhandled error")
return {
"statusCode": HTTPStatus.INTERNAL_SERVER_ERROR,
"body": json.dumps({"message": "Internal server error"})
}
try
: 정상 흐름 처리except ValueError
: 유효성 관련 예외except Exception
: 시스템 오류 등 모든 예외 캐치logger.warning
, logger.exception
: CloudWatch 로그로 기록에러 메시지가 항상 다른 구조로 나가면 클라이언트에서 처리하기 어렵다.
따라서 아래와 같은 통일된 구조로 API 응답을 구성하는 것이 좋다:
{
"code": 400,
"message": "필수 파라미터 누락",
"detail": "name 파라미터는 필수입니다"
}
또는 간단히:
{
"message": "Not authorized"
}
Pydantic을 활용하면 응답 모델도 일관되게 정의할 수 있다:
from pydantic import BaseModel
class ErrorResponse(BaseModel):
message: str
code: int
에러를 반환하는 것도 중요하지만, 무엇이 왜 에러였는지 로그로 남겨야 추후 디버깅이 가능하다.
aws_lambda_powertools.logging
의 Logger
를 사용하면 structured logging도 지원된다.
logger.warning("유효하지 않은 입력: %s", invalid_input)
logger.exception("예상치 못한 오류 발생")
→ 이후 CloudWatch 콘솔에서 Lambda 로그 확인 가능
팁 | 설명 |
---|---|
상태 코드 표를 만들어 두고 팀에서 공유 | 코드 리뷰/테스트 시 기준 마련 |
에러 메시지는 사용자 기준에서 친절하게 | "KeyError" 대신 "입력 값이 잘못되었습니다" |
모든 예외를 except Exception: 으로 처리하지 말고, 예측 가능한 오류는 따로 구분 | 400 / 422 / 403은 명확하게 나눠주기 |
개발 단계에서 logger.exception 적극 사용 | 배포 후 문제 추적에 핵심 |
에러 처리는 단순한 예외 캐치가 아니라, 서비스의 신뢰성과 사용성에 직접적인 영향을 주는 품질 요소다.
특히 Lambda 기반 API처럼 프레임워크 없이 동작하는 환경에서는 상태 코드 설계, 메시지 구조화, 로그 기록이 개발자의 책임이라는 점에서 더욱 중요하다.