Data shapes Required
Parse input once at the boundary
Turn outside input into a typed, valid object as soon as it arrives. Code after that point trusts the type and does not check again.
How to do it
Use a schema validator, such as zod, pydantic or Symfony Validator, in the controller, queue consumer or file reader. Reject bad input there with a clear error. Pass only the parsed object onward.
Example
# Bad: every function re-checks the raw dictionary
def book(data: dict):
if "email" not in data: raise ValueError("email")
# Good: parse once, then trust the type
class BookingRequest(BaseModel):
email: EmailStr
start: datetime
def book(request: BookingRequest): ...
import { z } from 'zod';
// Good: parse once, then trust the type
const BookingRequest = z.object({ email: z.email(), start: z.coerce.date() });
type BookingRequest = z.infer<typeof BookingRequest>;
function book(request: BookingRequest) { /* ... */ }
book(BookingRequest.parse(body));
How to check
Each request handler calls a parser before any other logic. A test sends a request with a missing and a wrong-typed field. It expects a 400 or 422 answer that names both fields, as in validation errors.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers architecture playbook: https://agentwranglers.se/playbook/architecture/data-shapes/parse-at-the-boundary.