openapi-chain

Supported behavior and boundaries

This is the maintained serialization contract. For usage, start with the getting-started guide; dated evidence lives in the qualification archive.

SurfaceCoreStrict
Fluent path treeOperation-derived types, scalar and flat-array path encodingSame type model with metadata-driven path encoding
Mixed templates and reserved segment namesTyped $path()Method names can be segments at nonconflicting nodes; $path() for remaining conflicts
Query objects/arraysSchema-free flat values and plain object expansion, or local extension; nested values rejectedOpenAPI form, delimited and deepObject styles
Whole-query querystringNot supported by the core typed inputOpenAPI 3.2 metadata and extension support
Headers/cookiesScalar and flat-array defaults or extension; structured values rejectedMetadata-driven styles/content; browser restrictions still apply
JSON/text/native request bodiesExplicit contentTypeSingle-concrete-media inference when metadata proves it
Structured URL-encoded/multipart bodyWhole-body extensionEncoding Objects and supported native Fetch representations
Vendor wire behaviorLocation/body extensions, then final request/transportSame order; metadata validation precedes serialization
Client headersStatic HeadersInit; functions rejectedStatic or per-request sync/async function
MiddlewareImplement in transportMiddleware composition and transport
Response parsingJSON/text defaultsJSON/text/binary defaults
StreamingExplicit response extension and matching declared data typeSame
Runtime JSON Schema validationApplication responsibilityApplication responsibility
Runtime response status/data validationExtension status must match actual response; schema data not validatedSame
Metadata compilationNot loadedSeparate compiler for 3.0/3.1/3.2 serialization metadata
External referencesNo document processingRejected: bundle/dereference first
Recursive schemasNo document processingOrdinary object recursion is allowed; non-inferable serialization cycles and depth over 128 fail explicitly

See extension invocation conditions for the differences between omitted, empty and populated query inputs.

Platform and type boundaries

The public type model supports fixed OpenAPI methods, including QUERY. Actual Fetch implementations can reject methods such as TRACE and GET/HEAD bodies. A custom transport must itself support any operation native Fetch cannot send. Browser Cookie headers, CORS and credentials follow browser policy; use credentials and server-set cookies for browser sessions.

Paths containing whole literal or encoded dot segments are rejected. Native Fetch would normalize them and change the endpoint. Use $path() for then, $path, mixed templates and repeated slashes. Core reserves all HTTP method names as segments. Strict allows a method name such as query as a segment when metadata declares that child path and the current node has no operation of that name; otherwise the operation takes priority. Core also requires $path() for trailing slashes (except the root /). Strict supports one trailing slash when its metadata identifies a unique template for the selected method. If /items and /items/ both declare GET, use $path() to choose; GET /items and POST /items/ can use the chain independently. Strict hides ambiguous methods from chain types and rejects ambiguous calls before transport. Exact $path() calls preserve slash structure.

Generated binary types and actual parser values must agree. Use an operation response extension for binary/stream/vendor formats and configure your generator's type mapping accordingly. A generic paths parameter is not runtime validation.

Metadata analysis caches shared schema subgraphs within each compilation. A 1,000,000-step work budget bounds traversal in addition to the 128-level depth limit; exceeding either fails explicitly. Compile large documents at build time. Caches are discarded between compilations.

Compiled metadata and paths must come from the same schema revision. Treat metadata as immutable while a client is alive. Strict routing is indexed at client construction; replace the client when the routing document changes.

Advanced multipart per-part headers, ordered/nested encoding and content-transfer encodings that native FormData cannot represent are rejected or require a whole body extension. Arbitrary OpenAPI 3.2 additionalOperations are not supported.

OpenAPI 3.2 Media Type Object references are resolved before compiling body and parameter-content serialization, including whole-query querystring content. Local references retain the referenced schema and Encoding rules; external, missing and cyclic references fail compilation.

Qualification scope

Local checks cover strict TypeScript, pinned real generator output, behavior and negative type tests, deterministic adversarial URL data, local HTTP, installed ESM/CJS tarballs, declaration resolution, coverage, core size and type-scale budgets. Chromium is a separate CI job. Node 22/24/26 and Windows/macOS/Linux are configured in the CI matrix; local success does not establish that those remote jobs passed.

This is a serialization support matrix, not a certification of every OpenAPI feature. Links, callbacks, webhooks, security-scheme execution, automatic auth, retry policy and complete schema validation are outside the client's built-in scope.

Reference contexts

Reference Objects cannot override serialization fields through sibling keys. OAS 3.0 schema references follow that same rule; OAS 3.1/3.2 Schema Object $ref siblings are combined conjunctively. Path Item references preserve disjoint fields and reject overlapping fields, whose behavior OpenAPI leaves undefined. Summary/description annotations do not affect the compiled serialization metadata.

Schema inference matrix

The compiler extracts serialization hints; it does not evaluate every JSON Schema keyword. Accepting a document is not a claim that every keyword influenced the result. This distinction matters most for multipart part defaults and form fields.

Schema structureCurrent inferenceApplication action
Explicit string, number, integer or booleanPrimitive kind; text default for ordinary valuesUse normal serialization for supported styles
Explicit object / propertiesObject kind and JSON part default; named properties supply field metadataKeep field serialization hints on named properties
Array with itemsArray kind; default part media is inferred from itemsCheck the supported style and element representation
Compatible allOf branchesCombines named properties conjunctively and derives available kind/media hintsPrefer explicit wire-relevant types; this is not general constraint solving
Explicit type values that disagree on object, array or scalar shape, whether declared on the schema itself or in its allOf branchesMultipart and URL-encoded declarations fail compilation with an error naming the operation, media type and property. Under */* or application/*, non-form selections such as JSON still work, and form serialization requires a whole-body extension. Compatible scalar types such as number with integer do not conflictGive a coherent serialization schema or preprocess the document; a runtime extension cannot recover a failed compilation
Local JSON Pointer referencesResolves against the OpenAPI document, including percent-encoded fragmentsBundle documents into this supported pointer form
OAS 3.0 schema reference siblingsIgnoredPut applicable schema constraints in an allOf branch
OAS 3.1/3.2 schema reference siblingsConjunctive analysis, including repeated acyclic referencesRepeated references are allowed; actual inference cycles still fail
Ordinary recursive object propertiesObject can be represented as a JSON partValidate recursive data separately if needed
Recursive allOf/items inference; excessive depth or workControlled compilation errorSimplify/preprocess the serialization schema
Nullable type array with one non-null typeUses the non-null type for hintsNull-value serialization remains subject to the location/body serializer
Multiple non-null types in typeNo kind or content-type hints are inferred; multipart/form and URL-encoded bodies require a whole-body extensionApplies through local references, allOf, and array items; explicit JSON serialization remains supported, including JSON selected from application/* or */*
oneOf; anyOf; conditional schemasNo complete branch analysis; Encoding keys may still name properties declared in alternativesDo not depend on automatic media inference; provide explicit media/encoding and a whole-body extension where necessary
additionalProperties / patternPropertiesNo per-key schema inference for dynamic property namesUse named properties or a body extension for schema-dependent map encoding
enum, bounds, required object properties, formats and response schemasNot a data-validation passValidate request/response data in application code
OAS 3.0 string format: binaryBinary part hintSupply the supported binary body value
Multipart contentEncodingMarks a named field for custom whole-body serializationUse a body extension capable of the intended wire format
External references or local anchor fragmentsRejected when resolvedBundle/normalize before compiling
$id resource scopes / $dynamicRefNo resource-scope or dynamic-reference evaluatorNormalize these constructs before relying on serialization inference

An explicit encoding.contentType controls supported field/part serialization; it does not turn unsupported schema constructs into a validator or bypass compiler errors. When inference is uncertain, verify the actual request body against the server's expected wire format. Whole-body extensions run after strict input validation and take responsibility for the complete body representation.

Binary bodies and multipart parts

Core and strict accept ArrayBuffer views (including Uint8Array, DataView and Node Buffer) for binary bodies. The view's byte offset and length are preserved; bytes outside a slice are not sent. Streaming request bodies still require an operation body extension and an appropriate Fetch implementation or transport.

Structured strict multipart bodies preserve File names when a declared part type requires replacing the File's media type. Arrays retain a separate part and name for each File. Anonymous Blob parts retain native FormData's default filename.

Native FormData, including the result of a body extension or strict structured multipart serialization, requires an unparameterized multipart/form-data selection. Fetch generates its own boundary and would drop any selected media parameters. Incompatible media types and explicit multipart parameters fail before transport. A whole-body extension returning encoded bytes or text can supply the exact representation and matching header instead.

An Encoding Object's single unparameterized media range, such as image/* or */*, is resolved from each Blob/File's matching concrete type. Missing, nonmatching or wildcard Blob types, parameterized ranges and multiple declared choices require explicit application serialization. Ranges are never emitted as part Content-Type values.

Generated textual multipart parts use UTF-8. Explicit charset=utf-8 (including quoted, case-insensitive spelling) is supported and retained; other charsets fail before transport. Pre-encoded Blob/ArrayBuffer/view values can carry another charset without re-encoding their bytes. The application is responsible for that encoding. A whole-body extension can also implement another character encoding.

Plain text/plain string parts remain normal form fields. Explicit media parameters require a Blob-backed part to retain its Content-Type; native FormData adds a filename to such parts. If the server requires a parameterized text part without a filename, use a whole-body extension to supply that exact representation. Style-based encodings follow their separate OpenAPI rules and ignore contentType.

Quoted commas in Encoding contentType parameter values remain part of one media declaration. Native Blob lowercases its type and cannot preserve every parameter value, so strict rejects case-sensitive values that would change and non-ASCII values that would be discarded. Case-insensitive charset spelling remains supported. Use a whole-body extension for part headers that native Blob cannot represent. See the File API type conversion.

Media recognition and text encodings

Default response parsing classifies the normalized media type before its semicolon-separated parameters. JSON parsing applies to application/json and +json suffix types; parameter values containing json or xml do not select a parser. Strict uses text for text/*, application/xml, +xml and application/x-www-form-urlencoded, and ArrayBuffer for other nonempty bodies. Core retains its text fallback. JSON sequences and other streaming formats need a response extension. Default text decoding follows Fetch's UTF-8 text() behavior; use a response extension for another response encoding.

Automatically generated request strings use UTF-8 across core, strict, JSON, text, form encoding and supported parameter-content serialization. A declared non-UTF-8 charset is rejected before transport. Quoted and case-insensitive UTF-8 labels are accepted; unrelated quoted parameters do not select a charset. Pre-encoded Blob/ArrayBuffer/view bodies remain byte-preserving, including under text media types. Body and location extensions retain responsibility for their chosen encoding. Merely changing a Content-Type header never transcodes bytes.

Core assumes the standard Fetch body classes supplied by supported Node versions and modern browsers, including when an application replaces the transport.

Strict serialization styles

LocationBuilt-in behavior
Pathsimple, label, matrix, explode and safe reserved expansion
Queryform, spaceDelimited, pipeDelimited, deepObject, explode, allowReserved, Parameter content
Headersimple, explode and Parameter content
CookiePrimitive form, OpenAPI 3.2 cookie, Parameter content
Query stringOpenAPI 3.2 in: querystring whole-query media serialization
BodyJSON, text, supported binary/native values, structured URL-encoded and multipart bodies
Encoding ObjectSupported content defaults and style / explode / allowReserved overrides

Styles still impose value-shape constraints; this table does not promise arbitrary nested object encoding. allowReserved takes effect only where OpenAPI applies it (query parameters, plus path parameters and form cookies in OpenAPI 3.2); elsewhere it has no effect, and explode has no effect on deepObject. Compound legacy cookie form values fail because the style's delimiter cannot faithfully represent a Cookie header. Invalid style/location combinations and unsupported representations fail explicitly. Use an operation-local extension where the application owns the exact wire format.

Strict validates required parameter locations, body presence, declared inputs and supported media. It does not validate enum/range constraints, required properties inside body objects, response data or undocumented response statuses. A response extension can add application validation; see the response contract.

Choosing core and migrating to strict

Follow the staged migration guide and offline comparison workflow. Verify the operations you actually use; do not infer compatibility from a document percentage or wait for core to fail.

Core rejects middleware, metadata and function-valued headers at construction, including JavaScript callers. Use openapi-chain/strict for these options; core applications can implement authentication and middleware in their transport. Explicit undefined is equivalent to omitting an option.

Absence of non-default style or explode is not proof of core compatibility. Check parameter location and value shape as well: a default simple object header requires a,b for { a: 'b' }, whereas core rejects the object without a header extension. Core also rejects object path and cookie values, and arrays or plain query objects containing nested arrays/objects, before transport rather than sending [object Object]. Flat arrays and flat plain query objects retain their schema-free defaults; they still require comparison with the declared OpenAPI style. Scalar path encoding, compound cookies, body encoding and response parsing also need review. A keyword search is only an initial screen.

When migrating, compile metadata from the same schema revision as the generated types, then check required/undeclared inputs, media selection, wire encodings and response consumers. Core requires explicit body contentType; strict can infer a single concrete declared media. Binary response consumers must account for strict's ArrayBuffer default instead of core's text fallback. Changing entry points is not an unconditional behavior-preserving migration.

On this page