Skip to content

Conversation

@rh-amarin
Copy link
Contributor

HYPERFLEET-500 - feat: introduce oapi-codegen

This PR introduces oapi-codegen to generate the go types from openapi.yaml schema instead of the Java openapi-generator tool.

This PR depends on the approval of: openshift-hyperfleet/hyperfleet-api-spec#21
The generated openapi.yaml from that PR is already introduced in this PR, with v1.0.2

The PR is organized in 3 commits:

@openshift-ci
Copy link

openshift-ci bot commented Jan 12, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci
Copy link

openshift-ci bot commented Jan 12, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign xueli181114 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

@rh-amarin
Copy link
Contributor Author

⏺ OpenAPI Code Generation Comparison

Overview

Aspect main/ (OpenAPI Generator) ogen/ oapi-codegen/
Files Generated 34 20 2
Lines of Code ~11,274 ~20,261 ~2,530
Runtime Deps None (stdlib only) ogen-go/ogen, go-faster/jx, OpenTelemetry oapi-codegen/runtime

  1. main/ - OpenAPI Generator (Java-based)

Type Style:

  type Cluster struct {
      CreatedTime time.Time `json:"created_time"`
      Name string `json:"name" validate:"regexp=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"`
      Spec map[string]interface{} `json:"spec"`
      Labels *map[string]string `json:"labels,omitempty"`  // pointer for optional
      Id *string `json:"id,omitempty"`
  }

Strengths:

  • ✅ No runtime dependencies - uses only stdlib (encoding/json)
  • ✅ Null-safety pattern with NullableCluster wrapper types
  • ✅ Constructor functions (NewCluster, NewClusterWithDefaults)
  • ✅ Validation in UnmarshalJSON - checks required properties
  • ✅ GetXxxOk() methods return tuple (value, bool) for presence checking
  • ✅ HasXxx() methods for optional field presence
  • ✅ ToMap() method for generic map conversion
  • ✅ Mature tooling - widely used, extensive documentation

Weaknesses:

  • ❌ Verbose - each model in separate file with many boilerplate methods
  • ❌ Pointer-based optionals (*string) - less idiomatic for Go
  • ❌ No built-in validation beyond required field checking
  • ❌ Flattens allOf schemas - loses composition structure
  • ❌ Java dependency - requires JVM to run generator

  1. ogen/ (Go-native generator)

Type Style:

  type Cluster struct {
      ID          OptString     `json:"id"`           // Optional type wrapper
      Kind        string        `json:"kind"`
      Labels      OptClusterLabels `json:"labels"`
      Name        string        `json:"name"`
      Spec        ClusterSpec   `json:"spec"`
      Generation  int32         `json:"generation"`
      Status      ClusterStatus `json:"status"`
  }

  type OptString struct {
      Value string
      Set   bool
  }

Strengths:

  • ✅ Opt[T] types for optionals - explicit presence tracking, no nil pointer issues
  • ✅ Built-in validation (oas_validators_gen.go) with structured errors
  • ✅ OpenTelemetry integration - tracing/metrics out of the box
  • ✅ Enum validation with MarshalText/UnmarshalText
  • ✅ High-performance JSON using go-faster/jx (no reflection)
  • ✅ Generated getters/setters for all fields
  • ✅ Pure Go toolchain - no JVM needed
  • ✅ Server + Client generation in same package
  • ✅ Type-safe response types (GetClusterByIdRes interface)

Weaknesses:

  • ❌ Largest output (~20k lines) - more code to maintain
  • ❌ Heavy runtime dependencies - ogen-go/ogen, go-faster/*, OTel
  • ❌ Learning curve - Opt[T] pattern different from idiomatic Go
  • ❌ Less flexibility - opinionated about patterns
  • ❌ Flattens allOf - doesn't preserve schema composition

  1. oapi-codegen/ (Go-native generator)

Type Style:

  type Cluster struct {
      // Preserves allOf composition!
      ClusterBase `yaml:",inline"`

      CreatedBy   openapi_types.Email `json:"created_by"`  // Typed email
      CreatedTime time.Time           `json:"created_time"`
      Generation  int32               `json:"generation"`
      Status      ClusterStatus       `json:"status"`
  }

  type ClusterBase struct {
      APIResource `yaml:",inline"`
      Kind string `json:"kind"`
      Name string `json:"name"`
      Spec ClusterSpec `json:"spec"`
  }

Strengths:

  • ✅ Most compact (~2.5k lines, 2 files) - minimal footprint
  • ✅ Preserves allOf composition - embedded structs match schema
  • ✅ Semantic types - openapi_types.Email instead of string
  • ✅ Lightweight runtime - just oapi-codegen/runtime
  • ✅ Pure Go toolchain - no JVM
  • ✅ ClientWithResponses - parsed response bodies with type safety
  • ✅ RequestEditorFn pattern - clean auth/middleware injection
  • ✅ Go-idiomatic - feels like handwritten Go code

Weaknesses:

  • ❌ No built-in validation - must add manually or use external
  • ❌ Pointer-based optionals (*string) - though less pervasive
  • ❌ Fewer accessor methods - direct field access preferred
  • ❌ Less observability - no OTel integration
  • ❌ Returns *http.Response - need ClientWithResponses for parsed bodies

Comparison Summary

Feature main/ ogen/ oapi-codegen/
Code Size Medium Large Small ✅
Runtime Deps None ✅ Heavy Light
Optional Handling Pointers Opt[T] ✅ Pointers
Validation Basic Full ✅ None
Schema Composition Flattened Flattened Preserved ✅
Observability None OTel ✅ None
Go Idiomaticity Medium Medium High ✅
Type Safety Good Excellent ✅ Good
Maintenance Java needed Go Go

Recommendation

For your use case (types + client only):

  • oapi-codegen is the best fit if you want minimal, Go-idiomatic code that preserves your schema composition (allOf inheritance). The embedded struct pattern (ClusterBase → Cluster) is clean and matches your OpenAPI design.
  • ogen is better if you need built-in validation, observability (OTel), or are building a complete server+client solution. The Opt[T] pattern is cleaner than nil pointers.
  • OpenAPI Generator (main/) is worth keeping if you need maximum compatibility or zero runtime dependencies, though the Java requirement and verbose output are downsides.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant