benzene.pydantic

Validate a handler's request with a pydantic model — the Python ecosystem's standard for parsing and validating request data. Distribution: benzene-pydantic (depends on benzene-core and pydantic). The core stays pydantic-free; this optional adapter is the one place the dependency lives.

pip install benzene-pydantic

validated

validated(model) wraps a handler so the decoded request body is validated into model (a pydantic BaseModel) before the handler runs. Apply @message(topic) above it and leave request_type unset — the raw body flows in and @validated checks it:

from benzene.core import message
from benzene.pydantic import validated
from benzene.results import Result
from pydantic import BaseModel

class PlaceOrder(BaseModel):
    sku: str
    quantity: int = 1

@message("orders:place")
@validated(PlaceOrder)
async def place(order: PlaceOrder) -> Result:
    return Result.created(order)

Responses

A pydantic model returned as a success payload is serialized by benzene.core's wire mapper via model_dump(by_alias=True). Note the asymmetry with a dataclass response: a dataclass's fields are auto-camelCased by the wire mapper, but a pydantic model is dumped under its own field names, so a plain model's order_id crosses the wire as order_id, not orderId. Give the model a camelCase alias_generator to put it back in the Benzene naming policy, exactly like a dataclass response:

from pydantic import BaseModel, ConfigDict
from pydantic.alias_generators import to_camel

class Receipt(BaseModel):
    model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
    order_id: str          # -> "orderId" on the wire

Exports

validated, format_validation_errors.

See also