Codecs and Serialization
Codecs and Serialization at the Askr server boundary, with validated input and explicit failure states.
Example
Define an executable schema once and reuse its JSON Schema representation in the HTTP contract and generated-client workflow.
import { schema } from '@askrjs/schema';
export const projectInput = schema.object({
name: schema.string({ minLength: 1 }),
ownerId: schema.uuid(),
});
const parsed = projectInput.safeParse(await request.json());
const jsonSchema = projectInput.jsonSchema;Request encoding
A Codec pairs a kind — json, text, urlEncoded, multipart, blob, arrayBuffer, stream, empty, or content — with the media types it produces and an optional validator. Calling .body(codec) on an endpoint builder wires that codec into request serialization, and content({ "application/json": json(), "multipart/form-data": multipart() }) lets a single endpoint accept more than one request format.
Response decoding
returns(codec) and returns(status, codec) register the codec used to decode each response status; the client picks whichever codec matches the response's actual status and content type. 204, 205, and HEAD responses must be declared with empty() — anything else against those statuses is treated as an unexpected body and fails decoding.
Dates and custom values
Because a validator only needs a safeParse(value) method, date parsing, custom scalar coercion, or a third-party validation library can be dropped straight into json(schema), a parameter spec's validator, or any other codec slot without an adapter layer. Whatever the validator's safeParse returns as data is what gets serialized on the way out and returned to the caller on the way in.
Failure diagnostics
A response with no codec registered for its status, a content type the registered codec doesn't declare, a payload that fails safeParse, or a non-empty body where empty() was required all produce a FailureResult with kind: "decode" rather than a thrown exception. The underlying cause — the validator's error, or a description of the mismatch — is available on result.error for logging or a bug report.