Lambda ハンドラーの型定義、どっちを使う? aws 노트
AWS Lambda 핸들러 타입 정의, 무엇을 쓸까? aws-lambda-typing vs powertools
AI로 Lambda 코드를 자동 생성하다 보면, 핸들러의 event, context 타입 정의가 제각각인 걸 한 번쯤 보셨을 겁니다.
어떤 코드에는 aws-lambda-typing이, 또 어떤 코드에는 aws-lambda-powertools가 쓰이죠. 겉으로 보기엔 둘 다 "타입 잘 잡아주는 라이브러리"처럼 보이지만, 실제로는 목적과 성격이 꽤 다릅니다.
이 글에서는 두 라이브러리의 차이를 정리하고, 어떤 상황에서 무엇을 선택하면 좋을지 실무 기준으로 정리해 보겠습니다.
aws-lambda-typing vs aws-lambda-powertools, 한눈에 비교
두 라이브러리는 모두 AWS Lambda 핸들러의 event, context 타입 정의를 제공한다는 공통점이 있습니다.
하지만 태생부터 방향성이 다릅니다.
aws-lambda-typing은 말 그대로 "타입 정의만" 가볍게 제공하는 패키지입니다. Python의 TypedDict를 이용해서 Lambda 이벤트와 컨텍스트의 형태를 정교하게 표현해 줍니다. 다른 기능은 없습니다.
반대로 aws-lambda-powertools는 "서버리스 개발용 종합 툴킷"입니다. 타입 정의는 그 안에 들어 있는 기능 중 하나일 뿐이고, 로깅, 트레이싱, 메트릭, 벨리데이션, 파라미터 관리 등 Lambda 개발에 필요한 베스트 프랙티스를 한 번에 제공합니다. 타입 구현 방식도 Data Class 기반이라 사용성 면에서 차이가 납니다.
정리를 하면 이렇게 볼 수 있습니다.
가볍게 타입 힌트만 쓰고 싶다면 aws-lambda-typing,
이미 Powertools를 쓰고 있거나, 서버리스 개발을 본격적으로 한다면 aws-lambda-powertools가 자연스러운 선택입니다.
aws-lambda-typing: 타입 정의만 필요한, 가장 미니멀한 선택
aws-lambda-typing의 목적은 단 하나입니다.
Lambda의 event, context, response 구조를 Python 타입으로 정확하게 표현하는 것.
예를 들어 SQS 이벤트 핸들러를 작성할 때는 이렇게 사용할 수 있습니다.
from aws_lambda_typing import context as context_, events
def handler(event: events.SQSEvent, context: context_.Context) -> dict:
for record in event["Records"]:
print(record["body"])
return {"statusCode": 200}여기서 events.SQSEvent는 TypedDict로 정의되어 있어, event["Records"][0]["body"] 같은 딕셔너리 접근을 할 수 있습니다. IDE에서 키 이름에 대한 보조는 어느 정도 받을 수 있지만, 기본적으로는 "딕셔너리를 건드린다"는 느낌에 가깝습니다.
지원하는 이벤트 타입도 꽤 다양합니다.
API Gateway V1/V2, SQS, S3, DynamoDB Streams, SNS, EventBridge, Kinesis, CloudWatch Logs 등 대표적인 Lambda 이벤트는 대부분 커버하고 있습니다.
무엇보다 장점은 패키지 크기가 아주 작다는 점입니다. 타입 정의만 들어 있으니, 의존성도 가볍고 배포 패키지 사이즈에도 거의 영향을 주지 않습니다.
"로깅도, 트레이싱도, 메트릭도 다른 방식으로 이미 다 하고 있고, 타입 힌트만 필요하다"
이런 상황이라면 aws-lambda-typing은 깔끔한 선택입니다.
aws-lambda-powertools: 타입 정의를 넘어서는 서버리스 개발 툴킷
aws-lambda-powertools는 이야기가 완전히 다릅니다.
여기는 처음부터 "AWS Lambda를 제대로 쓰기 위한 종합 도구"라는 목표를 가지고 만들어진 라이브러리입니다. 게다가 AWS 공식에서 제공·유지하고 있다는 점도 신뢰성을 더해 줍니다.
이 안에는 크게 두 가지 축이 있습니다.
하나는 이 글의 주제인 event, context에 대한 "타이핑 + 데이터 클래스" 기능,
또 하나는 서버리스에서 사실상 필수에 가까운 기능들, 예를 들면 다음과 같습니다.
구조화 로깅(Logger), X-Ray 트레이싱(Tracer), CloudWatch 메트릭, API Gateway/AppSync 라우팅, JSON Schema 검증, SSM/Secrets Manager 연동, SQS/Kinesis 배치 처리, 멱등성(Idempotency) 처리 등.
타입 정의만 필요한 시점에는 다소 과해 보일 수 있지만, Lambda를 조금만 본격적으로 쓰기 시작하면 "어차피 쓰게 되는 것들"이 여기에 모여 있습니다.
SQS 이벤트를 예로 보면 코드가 이런 형태가 됩니다.
from aws_lambda_powertools.utilities.data_classes import SQSEvent, event_source
from aws_lambda_powertools.utilities.typing import LambdaContext
@event_source(data_class=SQSEvent)
def handler(event: SQSEvent, context: LambdaContext) -> dict:
for record in event.records:
print(record.body)
return {"statusCode": 200}딕셔너리 접근 대신 event.records[0].body 같은 프로퍼티 접근을 쓸 수 있고, @event_source 데코레이터가 원시 이벤트(JSON)를 SQSEvent 데이터 클래스로 자동 변환해 줍니다.
"타입 정의"를 넘어, "이벤트를 편하게 다루는 방법"까지 제공하는 것이 powertools 쪽의 강점입니다.
event vs context, 두 라이브러리의 타입 차이를 정확히 이해하기
먼저 context부터 짚고 넘어가면, 생각보다 단순합니다.
aws-lambda-typing의 context.Context와 aws-lambda-powertools의 LambdaContext는 제공하는 프로퍼티가 거의 같습니다.
function_name, function_version, invoked_function_arn, memory_limit_in_mb, aws_request_id, log_group_name, log_stream_name, identity, client_context, get_remaining_time_in_millis() 같은 값들을 동일하게 쓸 수 있습니다.
두 라이브러리 모두 프로퍼티 접근 방식이고, IDE 자동 완성도 비슷하게 잘 동작합니다.
즉, context 타입만 놓고 보면 기능적인 차이는 사실상 없습니다. 어떤 걸 써도 크게 상관없습니다.
흥미로운 차이가 생기는 곳은 event입니다.
aws-lambda-typing은 TypedDict 기반이라 다음과 같이 딕셔너리 스타일로 접근합니다.
event["Records"][0]["body"]반면 aws-lambda-powertools는 데이터 클래스 기반이라 다음처럼 프로퍼티로 접근합니다.
event.records[0].body표면적인 문법 차이를 떠나, 이 선택이 가져오는 실질적인 차이는 꽤 큽니다.
Data Class vs TypedDict: 왜 powertools 이벤트 타입이 더 편할까?
데이터 클래스 기반 이벤트 타입의 가장 큰 장점은 "읽기 전용이라는 의도가 코드에 녹아 있다"는 점입니다.
aws-lambda-powertools의 이벤트 클래스들은 내부 필드가 @property로 정의되어 있어, 사실상 읽기 전용처럼 동작합니다. IDE도 이를 인지해서, 값을 바꾸려 할 때 경고를 줄 수 있습니다.
from aws_lambda_powertools.utilities.data_classes import SQSEvent
def handler(event: SQSEvent, context):
record = event.records[0]
record.body = "new value" # IDE에서 경고 (읽기 전용 프로퍼티)반대로 aws-lambda-typing의 TypedDict 기반 이벤트는 딕셔너리이기 때문에, 수정해도 아무런 경고가 없습니다.
from aws_lambda_typing import events
def handler(event: events.SQSEvent, context):
event["Records"][0]["body"] = "new value" # IDE 입장에선 그냥 dict 업데이트Lambda 이벤트 페이로드는 원래 "읽기 전용"으로 다루는 게 맞습니다.
그런데 딕셔너리로 쓰다 보면 무심코 값을 바꾸는 코드를 넣어버리기 쉽고, IDE도 이를 막아주지 못합니다.
데이터 클래스 + @property 조합은 이런 실수를 타입 레벨에서 막는 안전장치 역할을 합니다.
또 하나의 차이는 IDE 자동 완성 경험입니다.
데이터 클래스는 event.records[0].까지만 입력해도 body, message_id 같은 필드 후보를 바로 보여줍니다.
딕셔너리는 event["Records"][0]["과 같이 문자열 키를 직접 입력해야 하는데, 이때는 자동 완성이 잘 듣지 않아 키 이름을 외우거나 문서를 찾아보게 됩니다.
일상적으로 Lambda 코드 양이 많아질수록, 이 차이는 개발 피로도에 그대로 쌓입니다.
powertools 이벤트 타입이 빛나는 실전 예시
차이가 가장 실감 나는 부분은 "헬퍼 메서드"입니다.
powertools의 이벤트 데이터 클래스에는 특정 서비스에 특화된 편의 메서드가 여럿 포함되어 있습니다.
예를 들어 Kinesis 이벤트를 처리한다고 해 보겠습니다. Kinesis의 레코드 데이터는 Base64 인코딩된 상태로 들어오기 때문에, 보통은 다음과 같은 과정을 직접 구현해야 합니다.
Base64 디코딩 → 바이트를 문자열로 변환 → JSON 파싱.
하지만 KinesisStreamEvent 데이터 클래스를 쓰면 이 과정을 한 줄로 줄일 수 있습니다.
from aws_lambda_powertools.utilities.data_classes import KinesisStreamEvent
def handler(event: KinesisStreamEvent, context):
for record in event.records:
data = record.kinesis.data_as_json()
# Base64 디코딩 + JSON 파싱을 한 번에 처리CloudWatch Logs 이벤트도 마찬가지입니다.
원시 이벤트는 gzip + Base64 + JSON이 겹겹이 쌓여 있어 직접 처리하려면 코드가 지저분해지기 쉬운데, 데이터 클래스를 사용하면 다음 정도로 정리됩니다.
from aws_lambda_powertools.utilities.data_classes import CloudWatchLogsEvent
def handler(event: CloudWatchLogsEvent, context):
logs = event.parse_logs_data()
for log_event in logs.log_events:
print(log_event.message)aws-lambda-typing을 쓴다면 이 디코딩/파싱 과정을 전부 직접 구현해야 하고, 테스트 코드도 더 많아집니다.
Lambda를 여러 서비스와 연동할수록, powertools 데이터 클래스의 헬퍼 메서드가 체감되는 순간이 늘어납니다.
언제 powertools를, 언제 aws-lambda-typing을 선택할까?
실무에서 가장 고민되는 지점은 여기일 겁니다.
"우리 프로젝트에서는 뭘 기준으로 선택해야 하지?"
우선 powertools 쪽이 더 자연스러운 케이스부터 보겠습니다.
이미 aws-lambda-powertools를 도입했거나 도입할 계획이 있다면, 타입 정의도 powertools로 통일하는 것이 좋습니다. 로깅, 메트릭, 트레이싱, 파라미터 관리 등을 powertools로 가져가는 순간, 이벤트 타입만 따로 aws-lambda-typing으로 가져갈 이유가 사라집니다.
또 IDE의 자동 완성과 안전한 읽기 전용 모델(@property), Kinesis/CloudWatch Logs 같은 헬퍼 메서드를 적극 활용하고 싶다면 powertools가 훨씬 생산적입니다.
반대로 aws-lambda-typing이 어울리는 상황은 매우 명확합니다.
파이썬 배포 패키지 크기를 극단적으로 줄여야 할 때입니다.
예를 들어 함수당 배포 패키지 사이즈를 몇 MB 단위로 관리해야 하거나, 콜드 스타트에 예민한 초단기 실행 Lambda를 다수 운영하는 환경이라면 "타입 정의만 제공하는 초경량 패키지"라는 점은 충분히 매력적입니다.
다만 요즘에는 Lambda의 콜드 스타트 문제가 점점 줄어드는 추세라, 이 차이가 결정적인 요인이 되는 경우는 생각보다 많지 않습니다.
한 가지 확실한 건, 두 라이브러리를 섞어 쓰는 건 권장되지 않는다는 점입니다.
이벤트 타입은 aws-lambda-typing, context는 LambdaContext 같은 식으로 혼합하면, 의존성만 늘어나고 얻는 이득은 없습니다. 프로젝트 단위로 "우리는 이걸 쓴다"라고 하나로 정리하는 편이 좋습니다.
시사점: Lambda 타입 정의, 이제는 "통일"이 생산성이다
정리해 보면 선택 기준은 아주 단순합니다.
Lambda를 본격적으로 개발하고 있고, 로깅·트레이싱·메트릭·파라미터 관리 등도 함께 고민하고 있다면 aws-lambda-powertools로 통일하는 것이 가장 현실적인 선택입니다.
이벤트를 데이터 클래스로 다루면서 IDE 보조를 극대화하고, 읽기 전용 프로퍼티와 각종 헬퍼 메서드 덕분에 의도치 않은 버그를 줄일 수 있습니다. 무엇보다 "AWS 공식이 유지하는 서버리스 베스트 프랙티스 모음"을 그대로 가져다 쓸 수 있다는 점이 큽니다.
반대로
"우리는 다른 모니터링/로깅 스택을 쓰고 있고, 타입 힌트만 가볍게 있으면 된다"
"패키지 사이즈를 정말로 최소화해야 한다"
이런 상황이라면 aws-lambda-typing이 더 잘 맞습니다.
마지막으로, AI가 Lambda 코드를 생성할 때 두 라이브러리를 섞어서 가져오는 경우가 많기 때문에, 팀 차원에서 어느 쪽을 표준으로 쓸지 한 번 정해 두는 것을 추천합니다.
프롬프트나 코드 템플릿에 "우리 프로젝트에서는 aws-lambda-powertools(또는 aws-lambda-typing)를 사용한다"는 규칙을 명시해 두면, 새로 생성되는 코드의 품질과 일관성이 눈에 띄게 좋아질 것입니다.
출처 및 참고 : Lambda ハンドラーの型定義、どっちを使う? aws-lambda-typing vs aws-lambda-powertools - サーバーワークスエンジニアブログ
