Skip to content

OpenAPI Compatibility

Garret Premo edited this page Mar 31, 2026 · 2 revisions

OpenAPI Compatibility

This page describes which OpenAPI features apijack's code generator handles, which are recognized but produce limited output, and which are not yet supported.

Supported OpenAPI versions

apijack targets OpenAPI 3.0.x and OpenAPI 3.1.x. Both versions are parsed from a JSON spec fetched at generate time. The generator reads paths and components.schemas from the root spec object; no version-gating logic exists — features from either version are handled as encountered.


Supported features

✅ Supported | 🔶 Partial / recognized | ❌ Not supported

Type system

Feature Status Notes
string / integer / number / boolean integer and number both map to TypeScript number
object with properties Emits a TypeScript interface for named schemas; inline object literals for nested schemas up to depth 3
array with items Emits ItemType[]; union/intersection item types are wrapped in parens
$ref references Resolved recursively through components/schemas; circular references are safely handled via a visited set
Deeply nested $ref chains Chains like PostWithAuthorAndCommentsPostBaseUserAddressCoordinates are fully resolved
allOf (intersection / composition) Emits a TypeScript intersection type (A & B & { inline }); required arrays are merged across all parts; inline members with properties are expanded
oneOf / anyOf (unions) Emits a TypeScript union type (A | B | C); single-variant unions are unwrapped
Discriminated unions (oneOf + discriminator) Emits A & { discriminatorProp: "value" } | B & { ... }; discriminator mapping is used when present, falls back to schema name
enum (string) Emits string literal union type
enum (integer / mixed types) Supported (OAS 3.1) Each value is rendered as a literal; null values in enums are handled
nullable: true (OAS 3.0 style) Appends | null to the resolved type
type as array, e.g. ["string", "null"] (OAS 3.1) Non-null types are unioned together; null in the array appends | null
const (OAS 3.1) Emits a literal type alias (e.g. export type Status = "active")
prefixItems — tuple types (OAS 3.1) Emits [A, B, C]; open-ended tuples with items emit [A, B, ...C[]]
not — negation (OAS 3.1) Emits unknown for not-only schemas; @not annotation is added to the JSDoc
patternProperties (OAS 3.1) Emits an index signature [key: string]: PatternType | undefined with a JSDoc comment identifying the pattern
additionalProperties: true Emits [key: string]: unknown index signature
additionalProperties: <schema> Emits [key: string]: ResolvedType | undefined
$defs (OAS 3.1) Flattened into the main schema map before type generation
readOnly properties Flagged in JSDoc (@readonly); skipped entirely when generating CLI body flags so users cannot accidentally send server-generated fields
writeOnly properties Flagged in JSDoc (@writeonly)
deprecated (schema and operation level) Schemas get @deprecated in JSDoc; operations are prefixed with [DEPRECATED] in command descriptions and the client method gets @deprecated
default values Preserved in JSDoc (@default) on generated types; query parameter defaults appear in CLI help text
Format hints (date-time, email, uuid, uri, password, int32, int64, float, double, date, binary, etc.) Preserved in JSDoc (@format); surfaced in CLI flag descriptions for query parameters
minimum / maximum / exclusiveMinimum / exclusiveMaximum Preserved in JSDoc; surfaced in CLI help for query params
minLength / maxLength Preserved in JSDoc
pattern Preserved in JSDoc
minItems / maxItems / uniqueItems Preserved in JSDoc
multipleOf Preserved in JSDoc
minProperties / maxProperties Preserved in JSDoc
required fields Required body props become .requiredOption() in Commander; optional props become .option()
example values Preserved in JSDoc (@example)
description Used in JSDoc for types and in Commander command/option descriptions
title 🔶 Parsed and stored; not currently emitted in output

Parameters

Feature Status Notes
Path parameters Typed positional arguments in the generated client method; positional <arg> in the Commander command
Query parameters Typed optional params object in the generated client; --flag options in Commander
Path-level parameters Parameters defined at the path object level (not inside an operation) are merged with operation parameters; operation-level params override by name+in
Parameter style and explode 🔶 Parsed and forwarded in JSDoc; not applied to serialization — query params are always serialized as simple strings via URLSearchParams
Header parameters Parsed (in: 'header' is in the type definition) but not wired up to the generated client or CLI flags
Cookie parameters Type definition acknowledges in: 'cookie'; not generated
deprecated parameters No special handling at the parameter level

Request bodies

Feature Status Notes
JSON request bodies (application/json) Fully resolved; object schemas become individual --flag options; primitive bodies use a single -B flag
Primitive body (string, number, boolean) Emits a single -B <value> flag; type conversion (to number or boolean) happens in the generated action
Array-of-primitive body (string[], number[]) Emits -B <values> accepting comma-separated values
Object body (via $ref, allOf, oneOf, anyOf) All schema composition forms are resolved into a flat list of --flag options; oneOf/anyOf variant props are hidden by default and shown with -V
Array body (items are objects) The array is noted in the command description; flags build a single item and the action wraps it in an array
multipart/form-data Only application/json is extracted from requestBody.content; multipart endpoints are treated as having no body
application/x-www-form-urlencoded Same as multipart — only the JSON content type is read
Multiple content types per endpoint 🔶 Only application/json is used; other content types are silently ignored

Responses

Feature Status Notes
200 / 201 / 202 / 204 responses The first matching response with an application/json schema (checked in order: 200, 201, 202, 204) becomes the return type
Inline response schemas Schemas defined directly in the response object are resolved; not extracted into a named type
Response $ref Resolved through the schema map
void return for 204 / no content When no JSON schema is found in any successful response, the return type is void
Multiple success codes with different schemas 🔶 Only the first matching response code (200 → 201 → 202 → 204) is used; other status codes are ignored
Error response codes (4xx / 5xx) Error schemas are not used for type generation; the generated client throws { status, body } on non-OK responses
Response headers Response header definitions are ignored

Commands and grouping

Feature Status Notes
Tag-based command grouping The first tag on each operation determines the command group; multi-token tags (split on whitespace, /, :) create nested sub-groups
Operations without tags Fall back to a default group
HTTP method → verb mapping GET (no path param) → list, GET (with path param) → get, POSTcreate, PUTupdate, DELETEdelete, PATCHpatch
Verb deduplication When multiple operations under the same parent would get the same verb, the operationId is used as the command name instead
operationId required Operations without an operationId are skipped silently
HEAD / OPTIONS / TRACE methods Only GET, POST, PUT, DELETE, PATCH are processed

Not yet supported

Feature Notes
multipart/form-data File upload and mixed-part requests are not generated; endpoints that only accept multipart will appear to have no body flags
application/x-www-form-urlencoded Form-encoded bodies are ignored; only JSON bodies are generated
Multiple content types per endpoint Only application/json is consumed from requestBody.content and response content; other media types are silently skipped
Response headers Headers defined in response objects are parsed but not exposed in the client or CLI output
Cookie parameters (in: cookie) Recognized in the type definitions but not generated
Header parameters (in: header) Recognized in the type definitions but not generated
OAuth2 / OIDC security schemes The securitySchemes section of the spec is not read; auth is configured separately via apijack's AuthStrategy system
Callbacks and webhooks callbacks defined on operations are not processed
XML content type application/xml bodies and responses are not generated
Server variables (servers[].variables) The servers array is not used; the base URL comes from the apijack environment config
externalDocs Parsed and ignored; not surfaced in generated output
links in responses Not processed
security per-operation overrides Not read; authentication is applied uniformly via the configured AuthStrategy
Parameter in: header and in: cookie Not generated into client method signatures or CLI flags
title on schemas Parsed but not emitted in generated output
not with additional type constraints A not-only schema resolves to unknown; not combined with type constraints or properties is not evaluated semantically

Edge cases

The examples/edge-cases-api/ directory contains a deliberately tricky REST API that exercises the trickiest patterns the generator must handle:

  • Templated/paginated responses (Page<T> pattern with three separate wrapper schemas)
  • Discriminated unions with three variants, a shared base via allOf, and an explicit discriminator mapping
  • Deep three-way allOf composition mixing two named schemas with an inline object (AdminUser)
  • Poorly-defined, all-optional specs with vague field names
  • Conflicting and duplicate tag names using different separator characters (spaces, colons, slashes)
  • Multiple POST operations under the same tag, triggering verb deduplication
  • Primitive and array-of-primitive request bodies
  • Deeply nested $ref chains (five levels deep through PostWithAuthorAndComments)
  • Enums on nearly every model field
  • Empty endpoints with no params, no body, and a 204 response
  • Multiple success response codes with different schemas on the same operation
  • All constraint keywords (minLength, maxLength, minimum, maximum, pattern, minItems, maxItems)
  • readOnly, writeOnly, nullable, deprecated, default, example, and format on every schema type
  • additionalProperties: true and additionalProperties: <schema> side by side
  • Endpoints that intentionally use unsupported features (multipart, multiple content types, response headers) to verify they degrade gracefully

See examples/edge-cases-api/README.md for the full list of scenarios and examples/edge-cases-api/server.ts for the implementation.

Clone this wiki locally