I've been using 2 SDKs that were generated by OpenAPI generator in a separate packages that share an identical code that is duplicated in different packages foo, bar:
package foo
// there's the exact same piece of code under another package bar
// GenericOpenAPIError Provides access to the body, error and model on returned errors.
type GenericOpenAPIError struct {
...
model interface{}
}
// Model returns the unpacked model of the error
func (e GenericOpenAPIError) Model() interface{} {
return e.model
}
// Failure Provides information about problems encountered while performing an operation.
type Failure struct {
// List of errors which caused this operation to fail
Errors []Error `json:"errors"`
}
// GetErrors returns the Errors field value
func (o *Failure) GetErrors() []Error {...}
// Error Describes a particular error encountered while performing an operation.
type Error struct {
...
// A human-readable explanation specific to this occurrence of the problem.
Detail *string `json:"detail,omitempty"`
...
}
Separately, there's an app where I use both SDKs: foo, bar and extract the first error from a list of errors where I try to cast an error to each of SDK's error types and have to duplicate the code because of it. Is there a way to simplify it using 1.18 that supports generics?
import (
foo "..."
bar "..."
)
func getErrorMessage(err error) (string) {
result := err.Error()
if fooError, ok1 := err.(foo.GenericOpenAPIError); ok1 {
if fooFailure, ok2 := fooError.Model().(foo.Failure); ok1 {
fooFailureErrors := fooFailure.GetErrors()
// it's guaranteed to be non-empty and .Detail != nil
result = *fooFailureErrors[0].Detail
}
}
if barError, ok1 := err.(bar.GenericOpenAPIError); ok2 {
if barFailure, ok2 := barError.Model().(bar.Failure); ok2 {
barFailureErrors := barFailure.GetErrors()
// it's guaranteed to be non-empty and .Detail != nil
result = *barFailureErrors[0].Detail
}
}
return result
}
To start, I was thinking I could redeclare these common types as interfaces in my app's code like:
type GenericOpenAPIError interface {
Model() interface{}
}
...
type Failure interface {
GetErrors() []Error
}
type DetailedError interface {
GetDetail() string
}
and then cast directly to these interfaces, is that a reasonable approach?
if mainError, ok1 := err.(GenericOpenAPIError); ok1 {
var mainErrorModel = mainError.Model()
if failure2, ok2 := mainErrorModel.(Failure); ok2 {
var ff = failure2.GetErrors()
if len(ff) > 0 {
result := ff[0].GetDetail()
}
}
}
When I try to test it, it seems like
if failure2, ok2 := mainErrorModel.(Failure); ok2 {
this casting is not successful. How can I debug it? The problem seems to be related to the face that GetErrors is a method on pointer:
func (o *Failure) GetErrors() []Error {...}
and I don't use pointers here:
if failure2, ok2 := mainErrorModel.(Failure); ok2 {
This question seems to be related.