[Go Generation] Emit typed query-parameter structs for all construct packages
## 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 条评论