C.W.K.
Stream
Lesson 04 of 07 · published

Message Validation

~12 min · protocol, pydantic, validation

Level 0Poller
0 XP0/60 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

클라 input 절대 신뢰 금지

들어오는 모든 WebSocket message 가 입증 전엔 적대적. envelope, type, 모든 field, 길이 다 validate. Pydantic 이 한 decorator + 한 schema 로 structured validation, error 는 {type: 'error', code: 'validation_error', message: ...} 로 리턴 가능.

Literal 로 tagged union

Message type 별 Pydantic 모델 정의 후 Field(discriminator='type') 로 dispatch. 프레임워크가 type field 기반으로 옳은 모델 픽, 나머지 validate, typed 객체 리턴. 나쁜 message 는 handler 돌기 전 reject.

Code

Pydantic discriminated union·python
from pydantic import BaseModel, Field, ValidationError, field_validator
from typing import Literal, Annotated, Union, Optional

class ChatPayload(BaseModel):
    room: str
    text: str
    reply_to: Optional[str] = None

    @field_validator('text')
    @classmethod
    def text_ok(cls, v: str):
        v = v.strip()
        if not v:
            raise ValueError('empty')
        if len(v) > 5_000:
            raise ValueError('too long')
        return v

class ChatMessage(BaseModel):
    type: Literal['chat.message']
    data: ChatPayload

class JoinPayload(BaseModel):
    room: str

class RoomJoin(BaseModel):
    type: Literal['room.join']
    data: JoinPayload

InboundMessage = Annotated[
    Union[ChatMessage, RoomJoin],
    Field(discriminator='type'),
]

# In your handler
async def handle(ws, raw: dict):
    try:
        msg = pydantic.TypeAdapter(InboundMessage).validate_python(raw)
    except ValidationError as e:
        await ws.send_json({
            'type': 'error',
            'code': 'validation_error',
            'message': e.errors()[0]['msg'],
        })
        return
    if isinstance(msg, ChatMessage):
        await on_chat(ws, msg.data)
    elif isinstance(msg, RoomJoin):
        await on_join(ws, msg.data)

External links

Exercise

Pydantic validation 을 message type 셋에 추가. malformed chat.message (빈 text), 잘못된 type field ('chat.unknown'), 빠진 field 보내. 각각이 클라가 crash 없이 react 가능한 structured error 응답 만드는지 확인.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.