u/James_Keenan

▲ 5 r/golang

Struggling with method design for a CLI. What is part of a client library? What is part of cobra?

Say we have an internal platform with an exposed API. This is for creating testing environments, deploying new versions, etc.

  1. I have a generic `makeRequest` method that's a wrapper around httpClient.Do
  2. I have some method wrappers around those (c.Put, c.Get, etc...)
  3. Then I have the final client library methods. Say for Environment (basically a service catalog) it might be:

​

func (c *Client) Environment(ctx context.Context, environmentName string) (*APIResponse, error) {
queryParams := make(map[string]string)
endpoint := fmt.Sprintf("/api/environments/%s", url.PathEscape(environmentName))
return c.Get(ctx, endpoint, queryParams)
}

The commands/subcommands we want to support are, say

  1. get environment {name}
  2. list environments
  3. create environment {name}
  4. delete environment {name}
  5. etc.

So far we have an `internal/` directory and a `cmd/` directory. For this given platform, we have a similar package in both. One for handling the client communication, one for the cli itself, with cobra. The cli has other packages and commands/subcommands for operations in, say, AWS/GCP, etc.

I really, really want to center around best practices, go style, etc. I could list off plenty of rules about package naming, avoiding nesting, testing, panicking, error handling... But this, fundamental architecture design... I just don't know what's best. What's going to save us the most pain in the future?

  1. How specific should the api "client" library be in `internal`?
  2. How much goes into the `cmd/` companion package? (using cobra/viper)?
  3. Should all of those API use cases be in the client package, or the cmd package?

I just don't know.

reddit.com
u/James_Keenan — 5 days ago