Skip to content

OpenAPI 3.1 bidirectional fidelity — full import coverage + proper export (epic) #214

Description

@tonydspaniard

Context

Importing the real Swagger Petstore exposed that openapi:import (and its mirror, spec:emit-openapi) covers a useful subset of OpenAPI 3.1 and silently drops the rest. "The Petstore imports" was never proof of coverage — it imports ok=true while dropping every query parameter, every non-JSON body, all validation constraints, and all security. This epic tracks getting to bidirectional fidelity.

The standard (what "covered" means)

Literal 100% fidelity into generated code isn't achievable for a spec→code generator (callbacks, links, oneOf polymorphism, free-form additionalProperties have no clean Altair representation). The non-failing standard is:

Map everything representable; surface (warn/error) everything else — never silently drop. Emit spec-compliant OpenAPI on the way out. Round-trip stays stable.

Import coverage matrix (evidence-based, verified)

Mapped: objects (+nested), arrays, arrays-of-objects, top-level array bodies, scalars, enums→in:, internal $ref, properties/required, application/json bodies + responses, operationId/summary, x-altair-*.

Silently dropped (ok=true, no warning): query/header/cookie parameters (the parameters: array is never read); path-param schemas (always coerced to string); non-JSON bodies (multipart/form/xml/octet-stream); requestBody $ref and required; all validation constraints (format, min/maxLength, pattern, minimum/maximum, multipleOf, min/maxItems); additionalProperties, const, discriminator, not, prefixItems, nullable; security (schemes + requirements); servers, doc/op tags, deprecated, description, response headers/links, callbacks, webhooks (3.1), non-JSON responses.

Surfaced (errors/skips — not silent): external/file $ref, oneOf/anyOf/allOf in a request body, recursive $ref, bare scalar body.

Export gaps (spec:emit-openapi / OpenApiEmitter)

Mirror problems: all inputs emit into a single application/json request body (path/query/header distinction lost), validation rules are not emitted as schema constraints (emailformat, min:3minLength, in:enum, regexpattern), no security, no servers, path params not emitted as parameters.

Phased plan (each phase covers BOTH directions, own PR)

  • Phase 1 — stop silent loss. Import: a CoverageScanner warns on every dropped construct (params, non-JSON bodies, requestBody $ref, security, callbacks, webhooks, servers, composition). Makes the feature honest immediately.
  • Phase 2 — parameters. Import query/header params as inputs (tagged via x-altair-input-location, already reserved); give path params real types. Export: inputs whose location is path/query/header emit as OpenAPI parameters.
  • Phase 3 — validation fidelity. Import format + min/max/pattern/... → existing Altair\Validation rules (email, min, max, regex, between, in); requestBody required. Export: rules → schema constraints. (Round-trip-symmetric.)
  • Phase 4 — content & composition. multipart/form bodies, additionalProperties, oneOf/anyOf representation, external-$ref resolution/bundling.
  • Phase 5 — security & misc. security schemes ↔ auth/middleware hints; nullable, deprecated; fix singularize("findByStatus")findByStatu and action-y resource naming; path-param-type bug.

Acceptance

  • No import silently drops a construct — everything is mapped or warned/errored.
  • A richer real-world spec (Petstore + one with params/constraints/security) round-trips (openapi:roundtrip --check) with no silent loss.
  • docs/guides/openapi/coverage.md documents the matrix and is kept current per phase.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions