Use Credentials struct for NewClient
Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
This commit is contained in:
parent
78dc97a8d5
commit
6d615771cb
6 changed files with 34 additions and 52 deletions
10
README.md
10
README.md
|
@ -46,8 +46,8 @@ package main
|
||||||
import "github.com/vartanbeno/go-reddit/reddit"
|
import "github.com/vartanbeno/go-reddit/reddit"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
withCredentials := reddit.WithCredentials("id", "secret", "username", "password")
|
credentials := reddit.Credentials{ID: "id", Secret: "secret", Username: "username", Password: "password"}
|
||||||
client, _ := reddit.NewClient(withCredentials)
|
client, _ := reddit.NewClient(credentials)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ You can pass in a number of options to `NewClient` to further configure the clie
|
||||||
|
|
||||||
```go
|
```go
|
||||||
httpClient := &http.Client{Timeout: time.Second * 30}
|
httpClient := &http.Client{Timeout: time.Second * 30}
|
||||||
client, _ := reddit.NewClient(withCredentials, reddit.WithHTTPClient(httpClient))
|
client, _ := reddit.NewClient(credentials, reddit.WithHTTPClient(httpClient))
|
||||||
```
|
```
|
||||||
|
|
||||||
### Read-Only Mode
|
### Read-Only Mode
|
||||||
|
@ -69,10 +69,10 @@ client, _ := reddit.NewReadonlyClient()
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Configure the client from environment variables.</summary>
|
<summary>Configure the client from environment variables. When using this option, it's ok to pass an empty struct for the credentials.</summary>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
client, _ := reddit.NewClient(reddit.FromEnv)
|
client, _ := reddit.NewClient(reddit.Credentials{}, reddit.FromEnv)
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,8 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func run() (err error) {
|
func run() (err error) {
|
||||||
withCredentials := reddit.WithCredentials("id", "secret", "username", "password")
|
credentials := reddit.Credentials{ID: "id", Secret: "secret", Username: "username", Password: "password"}
|
||||||
|
client, err := reddit.NewClient(credentials)
|
||||||
client, err := reddit.NewClient(withCredentials)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,20 +7,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Opt is a configuration option to initialize a client.
|
// Opt is used to further configure a client upon initialization.
|
||||||
type Opt func(*Client) error
|
type Opt func(*Client) error
|
||||||
|
|
||||||
// WithCredentials sets the credentials used to authenticate with the Reddit API.
|
|
||||||
func WithCredentials(id, secret, username, password string) Opt {
|
|
||||||
return func(c *Client) error {
|
|
||||||
c.ID = id
|
|
||||||
c.Secret = secret
|
|
||||||
c.Username = username
|
|
||||||
c.Password = password
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithHTTPClient sets the HTTP client which will be used to make requests.
|
// WithHTTPClient sets the HTTP client which will be used to make requests.
|
||||||
func WithHTTPClient(httpClient *http.Client) Opt {
|
func WithHTTPClient(httpClient *http.Client) Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
|
|
|
@ -10,53 +10,44 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWithCredentials(t *testing.T) {
|
|
||||||
c, err := NewClient(WithCredentials("id1", "secret1", "username1", "password1"))
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, "id1", c.ID)
|
|
||||||
require.Equal(t, "secret1", c.Secret)
|
|
||||||
require.Equal(t, "username1", c.Username)
|
|
||||||
require.Equal(t, "password1", c.Password)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithHTTPClient(t *testing.T) {
|
func TestWithHTTPClient(t *testing.T) {
|
||||||
_, err := NewClient(WithHTTPClient(nil))
|
_, err := NewClient(Credentials{}, WithHTTPClient(nil))
|
||||||
require.EqualError(t, err, "*http.Client: cannot be nil")
|
require.EqualError(t, err, "*http.Client: cannot be nil")
|
||||||
|
|
||||||
_, err = NewClient(WithHTTPClient(&http.Client{}))
|
_, err = NewClient(Credentials{}, WithHTTPClient(&http.Client{}))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWithUserAgent(t *testing.T) {
|
func TestWithUserAgent(t *testing.T) {
|
||||||
c, err := NewClient(WithUserAgent("test"))
|
c, err := NewClient(Credentials{}, WithUserAgent("test"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, "test", c.UserAgent())
|
require.Equal(t, "test", c.UserAgent())
|
||||||
|
|
||||||
c, err = NewClient(WithUserAgent(""))
|
c, err = NewClient(Credentials{}, WithUserAgent(""))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, fmt.Sprintf("golang:%s:v%s", libraryName, libraryVersion), c.UserAgent())
|
require.Equal(t, fmt.Sprintf("golang:%s:v%s", libraryName, libraryVersion), c.UserAgent())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWithBaseURL(t *testing.T) {
|
func TestWithBaseURL(t *testing.T) {
|
||||||
c, err := NewClient(WithBaseURL(":"))
|
c, err := NewClient(Credentials{}, WithBaseURL(":"))
|
||||||
urlErr, ok := err.(*url.Error)
|
urlErr, ok := err.(*url.Error)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.Equal(t, "parse", urlErr.Op)
|
require.Equal(t, "parse", urlErr.Op)
|
||||||
|
|
||||||
baseURL := "http://localhost:8080"
|
baseURL := "http://localhost:8080"
|
||||||
c, err = NewClient(WithBaseURL(baseURL))
|
c, err = NewClient(Credentials{}, WithBaseURL(baseURL))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, baseURL, c.BaseURL.String())
|
require.Equal(t, baseURL, c.BaseURL.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWithTokenURL(t *testing.T) {
|
func TestWithTokenURL(t *testing.T) {
|
||||||
c, err := NewClient(WithTokenURL(":"))
|
c, err := NewClient(Credentials{}, WithTokenURL(":"))
|
||||||
urlErr, ok := err.(*url.Error)
|
urlErr, ok := err.(*url.Error)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.Equal(t, "parse", urlErr.Op)
|
require.Equal(t, "parse", urlErr.Op)
|
||||||
|
|
||||||
tokenURL := "http://localhost:8080/api/v1/access_token"
|
tokenURL := "http://localhost:8080/api/v1/access_token"
|
||||||
c, err = NewClient(WithTokenURL(tokenURL))
|
c, err = NewClient(Credentials{}, WithTokenURL(tokenURL))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, tokenURL, c.TokenURL.String())
|
require.Equal(t, tokenURL, c.TokenURL.String())
|
||||||
}
|
}
|
||||||
|
@ -74,7 +65,7 @@ func TestFromEnv(t *testing.T) {
|
||||||
os.Setenv("GO_REDDIT_CLIENT_PASSWORD", "password1")
|
os.Setenv("GO_REDDIT_CLIENT_PASSWORD", "password1")
|
||||||
defer os.Unsetenv("GO_REDDIT_CLIENT_PASSWORD")
|
defer os.Unsetenv("GO_REDDIT_CLIENT_PASSWORD")
|
||||||
|
|
||||||
c, err := NewClient(FromEnv)
|
c, err := NewClient(Credentials{}, FromEnv)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, "id1", c.ID)
|
require.Equal(t, "id1", c.ID)
|
||||||
require.Equal(t, "secret1", c.Secret)
|
require.Equal(t, "secret1", c.Secret)
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
libraryName = "github.com/vartanbeno/go-reddit"
|
libraryName = "github.com/vartanbeno/go-reddit"
|
||||||
libraryVersion = "1.0.0"
|
libraryVersion = "2.0.0"
|
||||||
|
|
||||||
defaultBaseURL = "https://oauth.reddit.com"
|
defaultBaseURL = "https://oauth.reddit.com"
|
||||||
defaultBaseURLReadonly = "https://reddit.com"
|
defaultBaseURLReadonly = "https://reddit.com"
|
||||||
|
@ -49,7 +49,7 @@ func DefaultClient() *Client {
|
||||||
// RequestCompletionCallback defines the type of the request callback function.
|
// RequestCompletionCallback defines the type of the request callback function.
|
||||||
type RequestCompletionCallback func(*http.Request, *http.Response)
|
type RequestCompletionCallback func(*http.Request, *http.Response)
|
||||||
|
|
||||||
// Credentials used to authenticate to make requests to the Reddit API.
|
// Credentials are used to authenticate to make requests to the Reddit API.
|
||||||
type Credentials struct {
|
type Credentials struct {
|
||||||
ID string
|
ID string
|
||||||
Secret string
|
Secret string
|
||||||
|
@ -110,7 +110,7 @@ func newClient() *Client {
|
||||||
baseURL, _ := url.Parse(defaultBaseURL)
|
baseURL, _ := url.Parse(defaultBaseURL)
|
||||||
tokenURL, _ := url.Parse(defaultTokenURL)
|
tokenURL, _ := url.Parse(defaultTokenURL)
|
||||||
|
|
||||||
client := &Client{BaseURL: baseURL, TokenURL: tokenURL}
|
client := &Client{client: &http.Client{}, BaseURL: baseURL, TokenURL: tokenURL}
|
||||||
|
|
||||||
client.Account = &AccountService{client: client}
|
client.Account = &AccountService{client: client}
|
||||||
client.Collection = &CollectionService{client: client}
|
client.Collection = &CollectionService{client: client}
|
||||||
|
@ -136,20 +136,23 @@ func newClient() *Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient returns a new Reddit API client.
|
// NewClient returns a new Reddit API client.
|
||||||
// Use an Opt to configure the client credentials, such as WithCredentials or FromEnv.
|
// Use an Opt to configure the client credentials, such as WithHTTPClient or WithUserAgent.
|
||||||
func NewClient(opts ...Opt) (*Client, error) {
|
// If the FromEnv option is used with the correct environment variables, an empty struct can
|
||||||
|
// be passed in as the credentials, since they will be overridden.
|
||||||
|
func NewClient(credentials Credentials, opts ...Opt) (*Client, error) {
|
||||||
client := newClient()
|
client := newClient()
|
||||||
|
|
||||||
|
client.ID = credentials.ID
|
||||||
|
client.Secret = credentials.Secret
|
||||||
|
client.Username = credentials.Username
|
||||||
|
client.Password = credentials.Password
|
||||||
|
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
if err := opt(client); err != nil {
|
if err := opt(client); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.client == nil {
|
|
||||||
client.client = &http.Client{}
|
|
||||||
}
|
|
||||||
|
|
||||||
userAgentTransport := &userAgentTransport{
|
userAgentTransport := &userAgentTransport{
|
||||||
userAgent: client.UserAgent(),
|
userAgent: client.UserAgent(),
|
||||||
Base: client.client.Transport,
|
Base: client.client.Transport,
|
||||||
|
@ -168,7 +171,7 @@ func NewClient(opts ...Opt) (*Client, error) {
|
||||||
|
|
||||||
// NewReadonlyClient returns a new read-only Reddit API client.
|
// NewReadonlyClient returns a new read-only Reddit API client.
|
||||||
// The client will have limited access to the Reddit API.
|
// The client will have limited access to the Reddit API.
|
||||||
// Options that modify credentials (such as WithCredentials or FromEnv) won't have any effect on this client.
|
// Options that modify credentials (such as FromEnv) won't have any effect on this client.
|
||||||
func NewReadonlyClient(opts ...Opt) (*Client, error) {
|
func NewReadonlyClient(opts ...Opt) (*Client, error) {
|
||||||
client := newClient()
|
client := newClient()
|
||||||
client.BaseURL, _ = url.Parse(defaultBaseURLReadonly)
|
client.BaseURL, _ = url.Parse(defaultBaseURLReadonly)
|
||||||
|
|
|
@ -35,7 +35,7 @@ func setup(t testing.TB) (*Client, *http.ServeMux) {
|
||||||
})
|
})
|
||||||
|
|
||||||
client, _ := NewClient(
|
client, _ := NewClient(
|
||||||
WithCredentials("id1", "secret1", "user1", "password1"),
|
Credentials{"id1", "secret1", "user1", "password1"},
|
||||||
WithBaseURL(server.URL),
|
WithBaseURL(server.URL),
|
||||||
WithTokenURL(server.URL+"/api/v1/access_token"),
|
WithTokenURL(server.URL+"/api/v1/access_token"),
|
||||||
)
|
)
|
||||||
|
@ -98,20 +98,20 @@ func testClientDefaults(t *testing.T, c *Client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewClient(t *testing.T) {
|
func TestNewClient(t *testing.T) {
|
||||||
c, err := NewClient()
|
c, err := NewClient(Credentials{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
testClientDefaults(t, c)
|
testClientDefaults(t, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewClient_Error(t *testing.T) {
|
func TestNewClient_Error(t *testing.T) {
|
||||||
_, err := NewClient()
|
_, err := NewClient(Credentials{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
errorOpt := func(c *Client) error {
|
errorOpt := func(c *Client) error {
|
||||||
return errors.New("foo")
|
return errors.New("foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = NewClient(errorOpt)
|
_, err = NewClient(Credentials{}, errorOpt)
|
||||||
require.EqualError(t, err, "foo")
|
require.EqualError(t, err, "foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue