Hey Morpheus team! Referrring to #3, though ideal I can see this is a big change given how much code is in this SDK, so what about wrapping the existing Client? This would provide choice of Client to users, and allow the receivers to be overridden on the new client (as and when) to provide the concrete returns Kevin mentioned and so negate the need for the user to perform the type assertion on all their API call results.
As the existing Client API is untouched we don't break the API for anyone, users can use the existing factory or the proposed V2 factory below.
I have this setup, and the tests passing.
package morpheus
// ClientV2 embeds a reference to Client we can use
type ClientV2 struct {
*Client
}
// NewV2Client creates a ClientV2 struct which embeds the exisitng Client so we have access to the
// Client receivers and the opportunity to override the receivers in a piecemeal fashion
func NewV2Client(url string, userAgent ...string) (client *ClientV2) {
clientUserAgent := "morpheus-terraform-plugin v0.1"
if len(userAgent) == 1 {
clientUserAgent = userAgent[0]
}
return &ClientV2{
&Client {
Url: url,
UserAgent: clientUserAgent,
},
}
}
// ListClouds receiver is overridden, the signature has been amended to accept a variadic argument (optional)
// and return the concrete ListCloudsResult in addition in addition the Response. The body is amended to parse and query
// params if a Request as been supplied, and perform the type assertion which allows the concrete return which negates
// need for the client performing the assertion on the interface type
func (client *ClientV2) ListClouds(req ...Request) (*ListCloudsResult, *Response, error) {
reqParams := hasRequest(req)
res, err := client.Execute(&Request{
Method: "GET",
Path: CloudsPath,
QueryParams: reqParams,
Result: &ListCloudsResult{},
})
return res.Result.(*ListCloudsResult), res, err
}
// helper to parse the params or return nil map
func hasRequest(req []Request) map[string]string {
var params map[string]string
if len(req) == 1 {
params = req[0].QueryParams
}
return params
}
Example tests, only ListClouds is overridden, but we can call Client receivers as the type is embedded.
func TestV2ListCloudsNoRequest(t *testing.T) {
client := getTestV2Client(t)
// ListClouds has been overridden, so returns the concrete type
// Note no Request argument
clouds, resp, err := client.ListClouds()
fmt.Printf("Clouds: %+v", clouds)
assertV2Response(t, resp, err)
}
func TestV2ListApps(t *testing.T) {
client := getTestV2Client(t)
// ListApps has NOT been overridden, so uses the Client ListApps
// with the existing signature which needs the type assertion in the client code
req := &morpheus.Request{}
resp, err := client.ListApps(req)
assertResponse(t, resp, err)
}
Just a thought, struck me as a low impact way to move to the concrete return types.
Hey Morpheus team! Referrring to #3, though ideal I can see this is a big change given how much code is in this SDK, so what about wrapping the existing Client? This would provide choice of Client to users, and allow the receivers to be overridden on the new client (as and when) to provide the concrete returns Kevin mentioned and so negate the need for the user to perform the type assertion on all their API call results.
As the existing Client API is untouched we don't break the API for anyone, users can use the existing factory or the proposed V2 factory below.
I have this setup, and the tests passing.
Example tests, only ListClouds is overridden, but we can call Client receivers as the type is embedded.
Just a thought, struck me as a low impact way to move to the concrete return types.