Repository navigation
Description
I have a simple oas3 file v3.1.0 with both const and regular objects. Here is my config cfg-schemas.yaml:
package: api
generate:
models: true
output: go/api/schemas.go
output-options:
skip-prune: true
name-normalizer: ToCamelCaseWithInitialisms
yaml-tags: trueAnd my schemas input file (simplified) schemas.yaml:
openapi: "3.1.0"
components:
schemas:
SomeConst:
type: string
const: "someconststringinput/fields/aes256"
OtherConst:
type: string
const: "otherconststringinput/subdata/ed25519"
Metadata:
type: object
properties:
name:
type: string
description: name of the input
description:
type: string
description: description of the input
digest:
type: string
description: SHA256 digest of the inputAnd then I run:
oapi-codegen -config ./cfg-schemas.yaml ./schemas.yaml
The output I get is the following:
// Package api provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.8.0 DO NOT EDIT.
package api
// Defines values for OtherConst.
const (
OtherconststringinputSubdataEd25519 OtherConst = "otherconststringinput/subdata/ed25519"
)
// Valid indicates whether the value is a known member of the OtherConst enum.
func (e OtherConst) Valid() bool {
switch e {
case OtherconststringinputSubdataEd25519:
return true
default:
return false
}
}
// Defines values for SomeConst.
const (
SomeconststringinputFieldsAes256 SomeConst = "someconststringinput/fields/aes256"
)
// Valid indicates whether the value is a known member of the SomeConst enum.
func (e SomeConst) Valid() bool {
switch e {
case SomeconststringinputFieldsAes256:
return true
default:
return false
}
}
// Metadata defines model for Metadata.
type Metadata struct {
// Description description of the input
Description *string `json:"description,omitempty" yaml:"description,omitempty"`
// Digest SHA256 digest of the input
Digest *string `json:"digest,omitempty" yaml:"digest,omitempty"`
// Name name of the input
Name *string `json:"name,omitempty" yaml:"name,omitempty"`
}
// OtherConst defines model for OtherConst.
type OtherConst string
// SomeConst defines model for SomeConst.
type SomeConst stringNotice that my Metadata component becomes type Metadata struct, while my peer SomeConst constant become type SomeConst string which can be access via the painfully named SomeconststringinputFieldsAes256 SomeConst = "someconststringinput/fields/aes256".
Since this is a constant, I don't care much to create a type SomeConst which is just a string, and then have a single object with a long name SomeconststringinputFieldsAes256 (looks like derived from the const value?) for it. I really am just looking for the simple:
const SomeConst = "someconststringinput/fields/aes256"I hope this describes the issue well?
Activity
mromaszewicz commentedon Sep 29, 2026
We can't tell your intent from your spec. You're asking for a type named
SomeConstwhich is astringand we provide it, and it has only one value, so we go through our standard enum generation.OpenAPI 3.1 has an idiom for declaring consts via oneof, here's one of our tests:
https://github.com/oapi-codegen/oapi-codegen/blob/main/internal/test/openapi31/spec.yaml#L96
The
titlewill go directly into code using that name. You could do something like this in your spec:The code will end up looking like this:
https://github.com/oapi-codegen/oapi-codegen/blob/main/internal/test/openapi31/openapi31.gen.go#L88
In your case, you would have a "Cipher" type, that's a string type.
We don't have a way right now to declare arbitrary global constants of a simple type.
deitch commentedon Sep 29, 2026
I think the
oneOfis a reasonable workaround. I will try to work with it.In terms of intent:
That is exactly it. I may be (likely am) misreading how my described intent gets interpreted. I look at this:
And I don't read it as "asking for a type named SomeConst which is a string". I read it as "SomeConst is a single thing, of type string with a constant value, so that is a straight-up const."
But I do get that even though in this scenario there is only one possible value for
SomeConst, and therefore my desire of:makes sense and is the only possible interpretation, the possibility for
SomeConstto be both of these:requires that both
SomeConstandOtherConstbe the same type of "thing" which sometimes has a single possible value, and sometimes multiple values. The only thing that satisfies that is a typed value astype SomeConst stringandtype OtherConst string, and therefore each possible value of it is a go const that is of the declared type.Given the above (and assuming I understood correctly), maybe a better way of saying this is, if a schema is a const, and only a single one (not
oneOf), then maybe there should be an option to collapse it down?In the meantime, documentation about this would be very helpful (and avoid more questions from the next one who hits this).
mromaszewicz commentedon Sep 30, 2026
Right, we could detect the special case of a const schema with a single value turning into a global const, however, at this point, we've shipped what we've got and I'd be breaking existing users. We're always stuck between a rock and a hard place here, trying to put concepts from a dynamic typing system into a statically typed language :)
Honestly, this problem is so complex, I sometimes wonder if people shouldn't just generate models with an LLM at this point.
deitch commentedon Sep 30, 2026
That is a strong point. I kind of realized it last night after I logged off (does that even exist, in the era of always-connected smartphones? 🤷♂️ ).
In any case, the summary basically is:
schemewill be atype. It might be astructor just a defined type for a string or int, etc.Just needs some examples to clarify. Is that more or less accurate?