zmdbzero-maintenance data layer
Docs Benchmarks Anti-patterns OpenAPI
Docs / Validation and contracts

Operations & ResponsesSupported

toOpenApi(httpContractIR, options) produces an OpenAPI 3.1 document from explicit operation objects. It is an output backend, not a route collector or a client-generation input.

One operation object#

Each HttpOperationIR already contains:

The renderer copies those facts. It does not inspect a handler or infer a default response.

import { toOpenApi } from '@zmdb/web/openapi';

const document = toOpenApi(compiled.ir, {
  info: { title: 'Blog API', version: '1.0.0' },
});

Two methods on one path#

Schemas are method-specific because they are referenced by each operation:

operations: [
  {
    operationId: 'listPosts',
    method: 'GET',
    path: '/posts',
    requestBody: undefined,
    responses: [/* GET schemas */],
  },
  {
    operationId: 'createPost',
    method: 'POST',
    path: '/posts',
    requestBody: {/* POST schema typeId */},
    responses: [/* POST schemas */],
  },
];

The emitted /posts path item has both get and post, but only post has a request body. No path-only lookup can attach the POST schema to GET.

Parameters#

LocationOpenAPI representation
pathrequired, simple, not exploded, reserved characters encoded
querycontract requiredness, form, exploded; arrays use repeated keys
headercontract requiredness, simple, not exploded
cookiecontract requiredness, form, exploded

The schema is the exact precomputed projection at the parameter's typeId. A missing type ID is an error, not an empty schema.

Bodies#

Contract kindOpenAPI schema
JSONreferenced schema projection
textstring
bytesbinary string
streambinary string
empty responseno content

A request body also carries its exact media type and required flag. An empty request body kind is invalid.

Responses#

Every declared status becomes one decimal key:

{
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": { "type": "object" }
        }
      }
    },
    "409": {
      "description": "Conflict",
      "content": {
        "application/problem+json": {
          "schema": { "type": "object" }
        }
      }
    },
    "204": {
      "description": "No content"
    }
  }
}

There is no inferred 200, range response, default, or undocumented fallback. Response headers retain their wire name, requiredness, schema, and optional description.

Operation identity and ordering#

operationId is copied from the contract key chosen by the application. It is not derived from method or path. Duplicate IDs and duplicate final method/path pairs are errors.

Documents sort by converted path, lower-case method, and operation ID. Responses sort numerically and security-scheme keys sort lexically, so unchanged input produces byte-identical JSON.

Fields not invented#

The renderer does not invent summaries, descriptions, tags, examples, callbacks, links, servers, or external documentation. Add prose metadata in a separate deterministic post-processing step if your application owns it; do not recollect route meaning.

Serving it#

serveOpenApi(document) returns () => document. Build once, commit or check the generated JSON in CI, and serve the prebuilt object.

---

See also: Generated HTTP Client · OpenAPI Generation · OpenAPI schemas · OpenAPI Security · API Versioning