Skip to content

Validation

The core ships a hook, not a schema library: validator(target, validate) takes any callable that turns raw data into a validated value (or raises). Failures become RFC 9457 problems (400).

from hayate import Hayate, validator

def require_title(data: dict) -> dict:
    title = data.get("title")
    if not isinstance(title, str) or not title.strip():
        raise ValueError("'title' must be a non-empty string")
    return {"title": title.strip()}

app = Hayate()

@app.post("/books", validator("json", require_title))
async def create(c):
    book = c.req.valid("json")   # the validated value
    ...

Targets: "json" (parsed body), "form" (urlencoded/multipart fields), "query" (search params).

msgspec

Because the hook is just a callable, schema libraries plug in directly — no adapter packages:

import msgspec

class BookIn(msgspec.Struct):
    title: str
    year: int

@app.post("/books", validator("json", lambda data: msgspec.convert(data, BookIn)))
async def create(c):
    book: BookIn = c.req.valid("json")
    return c.json({"title": book.title}, 201)

pydantic

from pydantic import BaseModel, TypeAdapter

class BookIn(BaseModel):
    title: str
    year: int

@app.post("/books", validator("json", TypeAdapter(BookIn).validate_python))
async def create(c):
    book: BookIn = c.req.valid("json")
    ...

A malformed JSON body short-circuits with a distinct message ("request body is not valid JSON") before your validator runs.