Closed bflad closed 4 years ago
Thanks for creating this this feature request @bflad. Adding the ability to get a slice of enums makes sense. I think this is something we can add to the code generation for enum types. Ideally we can port this idea to the v2 SDK tool.
Var - Exposing the slice directly as a package variable is a straight forward approach, but what impact that would have on the resident member, or binary since of the compile application to put all SDKs into memory. I'm not actually tested that, but is a hunch.
Type - Creating a new type with method is probably a good way to expose these as well. This is what the v2 SDK is doing with string aliases. Using structs is alternative to string aliases. Having a Values() []string
method on the type returning a slice would accomplish the goal. Using type alias or struct most likely has the least likely hood of name clashing with other generated identifier since the modeled enum shape has a unique name within the API. Either of these may instill some confusion in their usage since the type it self is not usable anywhere.
type Foo string
// or
type Foo struct{}
func (Foo) Values() []string {
return []string{
FooBar,
FooBaz,
}
}
const (
FooBar = "Bar" // Not actually of type `Foo`
FooBaz = "Baz"
)
Usage:
values := Foo("").Values() // Wish Go allowed scalar type zero value initialization with `{}`
values := Foo{}.Values()
Func - The final alternative I can think of is a standalone function that returns the slice of enum values. While simpler than the type alias or struct, a function name most likely will have a higher risk of clashing with some other generated identifier since a new unique name would need to be generated that is beyond the modeled names. Potential workaround for the name collisions would probably be some non-idiomatic naming scheme, e.g. Foo_Values()
.
func FooValues() []string {
return []string{
FooBar,
FooBaz,
}
}
Usage:
values := FooValues()
As much as the func approach would be nice, I think the risk of name collision will be prohibitive without some unique naming scheme for the function. The V2 SDK will address this feature via methods, since its already using a type alias.
Is your feature request related to a problem? Please describe.
(The below uses CodeBuild as an example, but this applies to all AWS Go SDK service packages and type string enumerations 👍 )
AWS service teams can and often do provide enumerations of available values for API parameters. For example, given these API References:
These are equivalent (and presumably generated in the API Reference documentation) from these in the API model:
The AWS Go SDK generators currently translate these enumeration values into Go constants:
Downstream in Terraform and the Terraform AWS Provider, one feature we provide is the ability to invalidate an infrastructure configuration upfront (during
plan
time in Terraform terminology), should an argument value not be in a predetermined slice of strings (amongst many other validation features). For example:Here is the above validation in the Terraform AWS Provider codebase:
These upfront validations are valuable to operators over finding configuration errors when making the API requests, potentially very far into creating their infrastructure or otherwise causing unexpected changes/downtime. Given the consequences, we have found over time that many operators have come to expect us to support this upfront validation at the expense of maintaining them with a slight delay as AWS service APIs support additional values.
This is super fuzzy metric (not representing reuse, etc.), but we have 483 of these string enumeration validators across our codebase today and many more places we don't support this validation where we could.
Describe the solution you'd like
We would like to reduce the manual work associated with including all known enumeration values at the time of the AWS Go SDK release in our codebase. It would be great if the AWS Go SDK service generators could output some form of retrieving all enumeration values for a given API model type.
A very naive approach could be generating a variable slice in addition to the constants, e.g.
Where downstream consumers such as our example above could be:
Otherwise, providing a new Go type for the enumeration with a receiver method for fetching the values, also could be an option:
Where downstream consumers such as our example above could be:
Describe alternatives you've considered
Additional context
Thank you for the consideration!