Return errors on nil credentials, move code around

Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
This commit is contained in:
Vartan Benohanian
2020-08-27 00:29:53 -04:00
parent c0f0cf8be6
commit c4faa00b94
6 changed files with 110 additions and 104 deletions
+21 -50
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@@ -31,45 +32,6 @@ const (
headerUserAgent = "User-Agent"
)
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map,
// since we'll only be modify the headers.
// Per the specification of http.RoundTripper, we should not directly modify a request.
func cloneRequest(r *http.Request) *http.Request {
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header, len(r.Header))
for k, s := range r.Header {
r2.Header[k] = append([]string(nil), s...)
}
return r2
}
// Sets the User-Agent header for requests.
type userAgentTransport struct {
userAgent string
Base http.RoundTripper
}
func (t *userAgentTransport) setUserAgent(req *http.Request) *http.Request {
req2 := cloneRequest(req)
req2.Header.Set(headerUserAgent, t.userAgent)
return req2
}
func (t *userAgentTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req2 := t.setUserAgent(req)
return t.base().RoundTrip(req2)
}
func (t *userAgentTransport) base() http.RoundTripper {
if t.Base != nil {
return t.Base
}
return http.DefaultTransport
}
// RequestCompletionCallback defines the type of the request callback function.
type RequestCompletionCallback func(*http.Request, *http.Response)
@@ -152,8 +114,11 @@ func newClient() *Client {
// NewClient returns a new Reddit API client.
func NewClient(creds *Credentials, opts ...Opt) (*Client, error) {
client := newClient()
if creds == nil {
return nil, errors.New("must provide credentials to initialize *reddit.Client")
}
client := newClient()
for _, opt := range opts {
if err := opt(client); err != nil {
return nil, err
@@ -164,6 +129,14 @@ func NewClient(creds *Credentials, opts ...Opt) (*Client, error) {
client.client = &http.Client{}
}
// We need to set a custom user agent, because using the one set by the
// stdlib gives us 429 Too Many Requests responses from the Reddit API.
userAgentTransport := &userAgentTransport{
userAgent: client.UserAgent(),
Base: client.client.Transport,
}
client.client.Transport = userAgentTransport
// todo...
// Some endpoints (notably the ones to get random subreddits/posts) redirect to a
// reddit.com url, which returns a 403 Forbidden for some reason, unless the url's
@@ -183,15 +156,13 @@ func NewClient(creds *Credentials, opts ...Opt) (*Client, error) {
}
}
if creds != nil {
client.ID = creds.ID
client.Secret = creds.Secret
client.Username = creds.Username
client.Password = creds.Password
client.ID = creds.ID
client.Secret = creds.Secret
client.Username = creds.Username
client.Password = creds.Password
oauthTransport := oauthTransport(client)
client.client.Transport = oauthTransport
}
oauthTransport := oauthTransport(client)
client.client.Transport = oauthTransport
return client, nil
}
@@ -204,7 +175,7 @@ func (c *Client) UserAgent() string {
return c.userAgent
}
// NewRequest creates an API request.
// NewRequest creates an API request with a JSON body.
// The path is the relative URL which will be resolves to the BaseURL of the Client.
// It should always be specified without a preceding slash.
func (c *Client) NewRequest(method string, path string, body interface{}) (*http.Request, error) {
@@ -253,7 +224,7 @@ func (c *Client) NewRequestWithForm(method string, path string, form url.Values)
return req, nil
}
// Response is a PlayNetwork response. This wraps the standard http.Response returned from PlayNetwork.
// Response is a Reddit response. This wraps the standard http.Response returned from Reddit.
type Response struct {
*http.Response
}