Skip to content

V2 Client with concrete return types? #23

@olliephillips

Description

@olliephillips

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions