ITADN

[Go Generation] Emit typed query-parameter structs for all construct packages

#759ClosedPragalvaXFREZ 创建于 2026-04-17
P
PragalvaXFREZcommented
## Context Meshery follows Schema-Driven Development: the structure of data and APIs is centrally defined in `schemas/constructs/**/api.yml`, and downstream consumers are expected to derive Go types from those specs rather than re-encoding parameter names as string literals. That contract currently breaks at the **operation-parameter** layer. Consumers in `meshery/meshery`, both the inbound HTTP handlers and the outbound `remote_provider` calls that forward requests upstream need schema-bound targets for query/path parameters. Today they must fall back to string literals, because the generator does not emit them: ```go // inbound handler: hard-coded literal orgID := q.Get("orgId") ``` ```go // outbound forwarding: hard-coded literal (currently misspelled as "orgID", // which is the class of drift a schema-driven pipeline is supposed to make // impossible) q.Set("orgID", orgID) ``` The casing drift surfaced as meshery/meshery#18638; meshery/meshery#18639 corrects the inbound literal. Neither side is schema-driven, both carry their own copy of `"orgId"`. The goal of this issue is to make **both consumers** schema-driven by providing the missing generator output, across the whole schemas repo. ## Scope: repo-wide, not a single construct This is not specific to `v1beta1/environment`. The same gap exists for every package that declares operations with parameters. A survey of the tree finds ~46 `api.yml` files under `schemas/constructs/`, spanning `v1alpha1`, `v1alpha2`, `v1alpha3`, `v1beta1`, and `v1beta2`, e.g. `organization`, `team`, `role`, `user`, `connection`, `design`, `model`, `component`, `relationship`, `event`, `catalog`, `environment`, and more. Every consumer that wants to be schema-driven against any of these packages hits the same missing primitive. Environment is the motivating example (meshery/meshery#18638) and a sensible first mover, but the fix belongs at the generator level and should apply to every package whose consumers are migrated. ## What schemas emits today The Go generation pipeline (`build/generate-golang.js`) runs `oapi-codegen -generate types` for every package. For any construct this produces: - Model structs (e.g. `Environment`, `Organization`, `Connection`, …). - Parameter **type aliases** only: `OrgIdQuery = string`, `Page = string`, `Pagesize = string`, `Search = string`, `Order = string`, and equivalents per construct. It does **not** produce per-operation parameter structs. There is no `GetEnvironmentsParams`, no `ListOrganizationsParams`, no `GetConnectionByIdParams`, and no `form:` struct tags anywhere in the generated Go. Consumers therefore have no schema-bound target to decode a `url.Values` into, or to encode from when forwarding upstream; they must name each parameter in a string literal at the call site. **Conclusion:** with the current generator configuration, schema-driven consumers are impossible for any construct package. The missing primitive, universally, is the per-operation `Params` struct with `form:`/`path:` tags. ## Proposal Enable server-mode generation in `oapi-codegen` so the per-operation parameter structs are emitted for every construct. The desired output, per operation, looks like: ```go type GetEnvironmentsParams struct { Search *Search `form:"search" json:"search,omitempty"` Order *Order `form:"order" json:"order,omitempty"` Page *Page `form:"page" json:"page,omitempty"` Pagesize *Pagesize `form:"pagesize" json:"pagesize,omitempty"` Filter *string `form:"filter" json:"filter,omitempty"` OrgId OrgIdQuery `form:"orgId" json:"orgId"` } ``` With these structs available, both consumers in `meshery/meshery` can bind parameters by schema tag (via `oapi-codegen/runtime` helpers or a tiny reflection-based decoder reading `form:` tags). The parameter name then exists in exactly one place in Go: the struct tag generated from `api.yml`. ## Implementation sketch In `build/generate-golang.js` (`generateGoModels`, around L1461), change the hard-coded `-generate types` to include a base server mode for all packages: ```js // before `-generate types ` + // after `-generate types,std-http-server ` + ``` One regeneration pass; every construct gets `Params` structs. All consumers can begin migrating at their own cadence. The downside is that every regenerated package grows by the `ServerInterface` and request/response wrapper types (dead exports under meshery's gorilla/mux routing, but retained safely by the existing `skip-prune: true`). ## Scope of generated artifacts `std-http-server` additionally emits `ServerInterface` and request/response wrapper types per package. These are unused by meshery (routing lives in gorilla/mux) but are harmless as dead exports: `skip-prune: true` is already set, so they survive codegen without forcing adoption. No breaking changes to existing consumers: the new types are additive, and every model type (`Environment`, `Organization`, `EnvironmentPage`, …) remains unchanged in name and shape. ## Which generator should own this output Each construct package contains two generated files today: - `zz_generated.helpers.go`: emitted by `build/lib/generated-go-helpers.js`, meshery-schemas' own custom generator. Used for outputs that have no OpenAPI analogue (e.g. `EventCategory()` lifecycle methods derived from schema annotations and conventions). - `<construct>.go`: emitted by `oapi-codegen` directly from `api.yml`. Per-operation parameter structs have a clear OpenAPI source of truth, the `parameters:` section of each construct's `api.yml`, so they belong with the spec-driven generator (`oapi-codegen`), not the custom helpers generator. Keeping generator responsibilities clean: the custom JS emits what the spec can't express; `oapi-codegen` emits everything the spec can. Extending `oapi-codegen`'s output (by enabling a server mode) also means consumers are automatically realigned whenever the spec evolves, matching the guarantee model types already enjoy. ## Downstream impact A follow-up PR in `meshery/meshery` will consume the newly generated `…Params` structs in both the inbound handlers and the outbound encoders in `remote_provider.go`, removing hard-coded query-parameter literals on either side of the request path. `environment` is the first consumer migration; others follow as the generator output lands. ## Related - meshery/meshery#18638: motivating bug (casing drift between two unsynchronized literals) - meshery/meshery#18639: inbound-only literal correction (still not schema-driven)
关闭于 2026-04-20 1 条评论