Skip to content

Instantly share code, notes, and snippets.

@rcosnita
Created July 11, 2023 08:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rcosnita/02e27db6df90561abcde6c26e4e3b7cf to your computer and use it in GitHub Desktop.
Save rcosnita/02e27db6df90561abcde6c26e4e3b7cf to your computer and use it in GitHub Desktop.
Provide a simple example for using golang generics for simulating strong type API http clients.
package main
import "fmt"
type Versionable interface {
Version() string
}
type Neg10_0_1 struct {
Attr10_1_0 string
}
func (v Neg10_0_1) Version() string {
return "10.0.1"
}
type Neg10_1_0 struct {
}
func (v Neg10_1_0) Version() string {
return "10.1.0"
}
type NegOperData11_2_5 struct {
Name string
}
func (v NegOperData11_2_5) Version() string {
return "11.2.5"
}
type NegOperData11_0_1 struct {
}
func (v NegOperData11_0_1) Version() string {
return "11.0_1"
}
type NegCompatibilityOperData interface {
NegOperData11_0_1 | NegOperData11_2_5
}
type NegCompatibility interface {
Neg10_0_1 | Neg10_1_0
}
type NegResult[NegData NegCompatibility, OperData NegCompatibilityOperData] struct {
Neg NegData
OperationalData OperData
}
type ResourceFetcher = func(id string) (interface{}, error)
type OperationalDataFetcher = func(id string) (interface{}, error)
var supportedResourceFetchers map[string]ResourceFetcher
var supportedOperationalDataFetchers map[string]OperationalDataFetcher
func init() {
supportedResourceFetchers = map[string]ResourceFetcher{}
supportedOperationalDataFetchers = map[string]OperationalDataFetcher{}
supportedResourceFetchers["10.0.1"] = func(id string) (interface{}, error) {
fmt.Println("fetching neg with major version 10")
return Neg10_0_1{Attr10_1_0: "cool attribute"}, nil
}
supportedOperationalDataFetchers["11.2.5"] = func(id string) (interface{}, error) {
fmt.Println("fetching neg operational data with major version 11")
return NegOperData11_2_5{Name: "cool neg operational data"}, nil
}
}
func FetchNeg[NegData NegCompatibility, OperData NegCompatibilityOperData](negId string) (NegResult[NegData, OperData], error) {
empty := new(NegData)
version := any(empty).(Versionable).Version()
resourceFetcher, found := supportedResourceFetchers[version]
if !found {
return NegResult[NegData, OperData]{}, fmt.Errorf("version %s of neg is not supported", version)
}
newNeg, err := resourceFetcher(negId)
if err != nil {
panic(err)
}
emptyOperData := new(OperData)
operDataVersion := any(emptyOperData).(Versionable).Version()
operDataFetcher, found := supportedOperationalDataFetchers[operDataVersion]
if !found {
return NegResult[NegData, OperData]{}, fmt.Errorf("version %s of neg operational data is not supported", operDataVersion)
}
// TODO(rcosnita) make some computation to determine the correct operdata id if needed.
newOperData, err := operDataFetcher(negId)
if err != nil {
panic(err)
}
return NegResult[NegData, OperData]{Neg: newNeg.(NegData), OperationalData: newOperData.(OperData)}, nil
}
func main() {
result, err := FetchNeg[Neg10_0_1, NegOperData11_2_5]("1234")
if err != nil {
panic(err)
}
fmt.Println(result.Neg.Version(), result.OperationalData.Version())
fmt.Println(result.Neg.Attr10_1_0)
fmt.Println(result.OperationalData.Name)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment