Skip to content

deps: evaluate migration from oapi-codegen to another tool for OpenAPI code generation #180

@ericfitz

Description

@ericfitz

Summary

Evaluate and plan migration from oapi-codegen to another OpenAPI code generator. This is a prerequisite for migrating the OpenAPI spec to 3.1+ (#87), since oapi-codegen has no path to 3.1 support.

Due to the stall in oapi-codegen's OpenAPI 3.1 development, the current top contenders are ogen and openapi-generator.

Background: oapi-codegen Is Blocked on OpenAPI 3.1

As of March 2026, oapi-codegen cannot support OpenAPI 3.1 and there is no clear timeline:

  • oapi-codegen issue #373 (open since 2021): OpenAPI 3.1 not supported.
  • kin-openapi issue feat: add security_reviewer query parameter to GET /threat_models #230 (open since 2020): The underlying parser lacks JSON Schema 2020-12 support required for 3.1.
  • Both projects say the work requires funding to proceed. A prior funding attempt fell through.
  • PR #1388 (switch to pb33f/libopenapi) was closed without merging — maintaining two parser backends was deemed infeasible without sponsorship.
  • Latest releases: oapi-codegen v2.6.0 (2026-02-27), kin-openapi v0.134.0 (2026-03-13) — neither includes any 3.1 work.
  • TMI's current dependencies (runtime v1.2.0, gin-middleware v1.0.2, kin-openapi v0.134.0) are already at latest versions.

Candidate 1: ogen

ogen is a Go-native OpenAPI code generator.

Strengths

  • OpenAPI 3.1 parsing: Can parse 3.1 documents (with caveats — see limitations)
  • Type-safe responses: Each operation returns specific response types, providing compile-time checking
  • Built-in OpenTelemetry: Tracing and metrics out of the box
  • Code-generated static router: Better performance than runtime routing
  • No reflection JSON encoding: Uses go-faster/jx for better performance
  • Operation grouping: x-ogen-operation-group vendor extension for logical handler interfaces
  • Active development: 2,025 stars, regular releases (latest v1.20.1, Feb 2025), 4,826 commits

Known Limitations and Risks

Critical for TMI

  1. No Gin integration — ogen generates a standalone http.Handler using stdlib net/http. TMI's entire Gin middleware stack (JWT auth, CORS, resource authorization, request tracing) would need to be rewritten as net/http middleware.
  2. No WebSocket support — ogen is purely REST/HTTP. TMI's WebSocket collaborative editing must be handled outside ogen, mounted separately on the HTTP mux.
  3. JSON Patch not supported (ogen issue #1587, closed without fix) — ogen skips operations with application/json-patch+json content type. TMI uses JSON Patch for partial updates. Requires workaround.
  4. Required field validation not generated (ogen issue #1407, open 6+ months) — significant correctness/security gap.
  5. allOf + nullable generates broken code (ogen issue #1512, open) — TMI uses allOf extensively for schema composition.
  6. Nested sum types generate non-compilable code (ogen issue #1480, open) — TMI's diagram cell types have nested unions.
  7. Discriminator with duplicate mappings (ogen issue #980) — TMI has multiple node shapes mapping to the same Go type, which is already a pain point with oapi-codegen.

OpenAPI 3.1 Gaps

  1. Type array syntax not supported (ogen issue #1617, open) — type: ["string", "null"] fails to parse. Workaround: use oneOf with type: "null" instead.
  2. unevaluatedProperties — no evidence of support. This is the main 3.1 feature TMI needs (deps: migrate to OpenAPI 3.1+ and use unevaluatedProperties for strict validation #87).

Architectural Impact

  1. All-or-nothing generator — unlike oapi-codegen (which lets you bring your own router via Gin/Echo/Chi adapters), ogen generates the router, handler interface, request/response encoding, and validation as a monolith.
  2. Optional fields use wrapper types (OptString, NilString, OptNilString) instead of pointers — changes how every optional field is handled.
  3. Custom JSON marshaling may need adjustment due to go-faster/jx instead of encoding/json.

Project Health

  • Bus factor: 2-3 — tdakkota (1,767 commits), ernado (1,512 commits), shadowspore (599 commits)
  • No corporate sponsor or foundation backing
  • 117 open issues, some critical bugs open 6+ months
  • Community: Telegram group (no Discord/Slack)

Candidate 2: openapi-generator

openapi-generator is the OpenAPI Initiative's official code generator, supporting 40+ languages including Go.

Strengths

  • Full OpenAPI 3.1 support (since v7.0)
  • Mature and battle-tested — 23k+ stars, large contributor base, corporate backing
  • Broad ecosystem — extensive template system, active community
  • Multiple Go server generatorsgo-server, go-gin-server, go-echo-server
  • Gin server generator available — could reduce middleware migration effort vs ogen

Known Limitations and Risks

  1. Java dependency — requires JVM to run the generator (Docker image available as alternative)
  2. More boilerplate — generates more opinionated/verbose code than oapi-codegen or ogen
  3. Go output quality — historically the Go templates have been less idiomatic than purpose-built Go generators; needs evaluation with current version
  4. Template maintenance — Go-specific templates may lag behind the main project
  5. Generated code style — may differ significantly from oapi-codegen's patterns, requiring substantial handler rewrites

Needs Investigation

  • Quality of generated Go server code with current templates
  • Gin server generator compatibility with TMI's middleware patterns
  • Discriminated union / allOf handling in generated Go code
  • JSON Patch support
  • How WebSocket endpoints would be handled alongside generated routes

Migration Effort Estimate

Regardless of which tool is selected, this would be a high-effort migration affecting most of the API layer:

  • Evaluate generated code from both candidates against TMI's current spec
  • Rewrite or adapt middleware stack (scope depends on tool choice)
  • Adapt all handler implementations to new interface patterns
  • Handle WebSocket endpoints outside generated router (if applicable)
  • Implement JSON Patch workaround (if applicable)
  • Adjust optional field handling (if applicable)
  • Verify discriminated union code generation works for TMI's cell types
  • Verify allOf composition works for TMI's schema hierarchy
  • Update all tests
  • Benchmark performance comparison

Other Options

  1. Wait for oapi-codegen — indeterminate timeline, both upstreams need funding.
  2. Contribute to oapi-codegen/kin-openapi — fund or code the 3.1 support directly.
  3. Hybrid approach — use a new generator for new endpoints while keeping oapi-codegen for existing ones during transition (increases complexity).

Tasks

  • Generate code from TMI's OpenAPI 3.0.3 spec using ogen — identify what breaks
  • Generate code from TMI's OpenAPI 3.0.3 spec using openapi-generator (go-gin-server) — identify what breaks
  • Compare generated output quality, idiomatic Go, and migration effort for both
  • Prototype middleware migration (JWT auth + one resource middleware) with the leading candidate
  • Assess whether blocking bugs in the chosen tool can be worked around
  • Make go/no-go decision
  • If go: create detailed migration plan with phased approach

Blocks

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    apiAPI design and implementationdependenciesPull requests that update a dependency fileenhancementNew feature or request

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions