Skip to content

Serialization

compileSerializer for fast JSON output and toJsonSchema for OpenAPI and tooling.

AI generated, pending review Updated 10 days ago · Flare 0.3

Validation and serialization are separate in @flare-ts/lib. Everyday request handling needs only safeParse. Reach for the serializers when you need encoded JSON output or a schema description for tooling.

ExportSummary
compileSerializerCompiles a fast (doc: JsonValue) => string function from a schema token
toJsonSchemaReturns a JSON Schema Draft 7 object for OpenAPI or docs generators

Both accept an OpaqueSchemaToken (any schema() or model() token).

import { compileSerializer, schema, int, text } from "@flare-ts/lib/schema";
const serialize = compileSerializer(schema({ id: int, name: text }));
serialize({ id: 1, name: "Ada" }); // JSON string

Dedicated codegen covers flat objects, top-level schema([Item]) arrays, nested tokens, and primitive array(...) fields. Record and discriminated-union descriptors fall back to a JSON.stringify delegate: same calling shape, but no fast path and no declared-field filtering, so undeclared properties pass through.

Compiled output emits only declared fields, and str/uuid fields skip the escape scan: a quote or newline that reaches a str field produces broken JSON on the consumer side, while text is always escaped. Keep str to values you control and text for anything user-shaped.

Emitting only declared fields is also a leak boundary. Return a database row straight from a handler and whatever reaches JSON.stringify ships with it: a password_hash, an internal flag, a column a later migration joined in that no one revisited the response shape for. A compiled serializer writes the fields its schema names and never reads the rest, so a property you never declared cannot ride along in the payload. The record and discriminated-union fallback is the exception noted above, since it delegates to JSON.stringify; keep a response that depends on this filtering to a flat object or top-level array.

In a Flare HTTP app, response contracts call compileSerializer at route build time when you declare a response entry. model() classes cache a compiled serializer on the class for the direct-return path. Outside HTTP, call compileSerializer yourself on any token.

import { toJsonSchema, schema, int, str } from "@flare-ts/lib/schema";
const jsonSchema = toJsonSchema(schema({ id: int, name: str }));

Supports flat objects, top-level arrays, records (additionalProperties), and discriminated unions (anyOf). Each primitive’s jsonSchema metadata flows through verbatim.

Use this when exporting API descriptions, generating client SDKs, or feeding validators that speak JSON Schema. It describes the token’s shape; it does not validate runtime payloads (use safeParse for that).

When a model() or schema() token is on a route contract’s response map, returning a plain object through this.ok(body), this.created(body), or new FlareResponse(status, body) uses the per-status compiled serializer. Without a matching response entry, the body uses JSON.stringify.

Inbound bodies still parse through safeParse on the contract body token before your handler runs. Serialization only affects outbound encoding.

See HTTP responses for contract response serializers and return-value rules.