I have a library package that calls out to an web service, to authenticate credentials. It’s basically this:
package myauthsvc
// Client object
type Client struct {
AccessToken string
Secret string
}
func (c *Client) Authenticate(userID string, secret string) (bool, error) {
// do some http call, return the result
return false, nil
}
It’s working fine, but obviously hard to mock and not idiomatic. I’m reasonably clear about interfaces, when used between packages. But I’m getting confused about struct embedding specifically when it comes to a library package.
If I want to improve my implementation, is this correct?
package myauthsvc
type ClientInterface interface {
Authenticate(userID string, secret string) (bool, error)
}
type Client struct {
AccessToken string
Secret string
ClientInterface
}
func (c *Client) Authenticate(userID string, secret string) (bool, error) {
// do some stuff
return false, nil
}
func NewClient(token string, secret string, ci ClientInterface) *Client {
return &Client{token, secret, ci}
}
Firstly, The NewClient method is defined in the package, but outside the type/interface.
Secondly, the Authenticate method has a receiving type of Client. And I think this is where my lack of understanding is. Is there something implicit that means Client ‘conforms’ to ClientInterface, and selector shorthand is causing Client.Authenticate == Client.ClientInterface.Authenticate?
Lastly, if my library package is self-contained but I want to be able to make it easy for other developers to mock the methods, how does the implementation look?
package main
import (
"github.com/thisdougb/myauthsvc" // this repo is just as an example, doesn't really exist
)
func test() {
c := myauthsvc.NewClient("userid", "secret", ci) // <- where does ci come from?
}
How do I create ‘ci’ when creating a new client?
I have read through solid-go-design
And also type-embedding
thanks for help.