I want to abstract the logic for oauth authentication and I've built the following code:
provider, _ := utils.ChooseProviderFromString(data.Provider)
user, _ := provider.TryLogin(OAuthAccessToken)
The provider comes as a string from the client (e.g facebook, github, google, whatever). Then we pass it to the ChooseProviderFromString method and returns the corresponding struct, and then we try to login.
So good so far as an idea, but yet I am stuck.
type OAuthAuthenticator interface {
TryLogin(accessToken string) (WHAT_TYPE_DO_I_NEED_HERE, error)
}
type FacebookAuthenticator struct {
accessToken string
}
func (fbAuth *FacebookAuthenticator) TryLogin(accessToken string) (*FacebookUserResponse, error) {
return GetFacebookUser(accessToken)
}
func ChooseProviderFromString(provider string) (OAuthAuthenticator, error) {
if provider == "facebook" {
return &FacebookAuthenticator{}, nil
}
return nil, errors.New("invalid provider")
}
You see that we choose the correct provider and return a new struct from it, similar to a factory. The problem is that I can't finish my idea, since I've got no clue what type I should write for the login response: TryLogin(accessToken string) (WHAT_TYPE_DO_I_NEED_HERE, error)
If we pass facebook as a string, we will return a new FacebookAuthenticator. When we call TryLogin it has to detect the authenticator and return the correct UserResponse (FacebookUserResponse, GithubUserResponse etc)
How can I fix this?