Shape Checks at the Boundary
A function that accepts unknown and returns a typed value must validate the shape. Validation libraries (Zod, Yup, io-ts, Effect Schema) have proliferated; each works well in isolation; coupling the domain to one of them is the move teams regret two years later when they want to swap. @frenchexdev/ddd-schema-validation reifies schema validation as a port with a Zod adapter so the domain's call sites stay stable while the library underneath is replaceable.
What ddd-schema-validation Reifies
The port reifies one operation: given an unknown input, return either a typed value or a typed failure. The library underneath decides how the schema is declared (Zod's chainable API, Yup's object schemas, custom JSON Schema), but the port's signature is the same: parse(input: unknown): Result<TParsed, ValidationFailure>.
The discipline reflects the corpus's Port/Adapter discipline. Schema validation is infrastructure — it deals with foreign byte shapes coming in from outside the domain. The domain's job is to reject malformed inputs before they reach an aggregate constructor; the schema-validation port is the place that rejection happens.
The pattern is small. The runtime declares the port shape. The Zod adapter implements parse against Zod schemas. A future Yup adapter would implement the same parse against Yup schemas. The aggregate's caller (an application service, a factory, an HTTP route handler) invokes the port without knowing which adapter is wired.
The Runtime: ddd-schema-validation and adapter
Two packages — ddd-schema-validation and ddd-schema-validation-zod-adapter — both M4/M5 stubs pinned to SchemaShapeValidationRequirement. Zod is the chosen first substrate — TypeScript-native, decent error shapes, widely adopted.
Cross-Links
- Invoked by
@Adapterat boundary points — every HTTP route, message-bus handler, file ingest pipeline parses input through the port before it reaches domain code. - Used by
@Factoryfor input shape checks; the factory'sstart(...)method takes raw inputs, validates them through the schema port, then proceeds. - Composes with
@DesignByContract— schema validation is the shape precondition; DbC's@Preis the value precondition that runs on already-shape-valid inputs. - Lives behind
@Port/@Adapter; the conformance suite verifies that adapters produce the same typed failures for the same inputs across substrates.
Back to the series index.