# Codecs and Serialization

> Codecs and Serialization at the Askr server boundary, with validated input and explicit failure states.

Source: [https://askrjs.com/docs/http-contracts/codecs](https://askrjs.com/docs/http-contracts/codecs)

Status: stable. Packages: @askrjs/askr.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

Define an executable schema once and reuse its JSON Schema representation in the HTTP contract and generated-client workflow.

```tsx
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.

## Documentation navigation

[Previous](https://askrjs.com/docs/http-contracts/results-and-errors/index.md) | [Next](https://askrjs.com/docs/http-contracts/client-middleware/index.md)
