2016-06-12 22:39:00 +00:00
|
|
|
package footballdata
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2016-06-13 17:46:27 +00:00
|
|
|
"errors"
|
2016-06-12 22:39:00 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
)
|
|
|
|
|
2016-06-25 10:15:58 +00:00
|
|
|
/*
|
|
|
|
Provides a high-level client implementation to talk to the API that football-data.org offers.
|
|
|
|
|
2016-06-26 10:57:14 +00:00
|
|
|
A new instance of Client will by default use the default HTTP client and no
|
|
|
|
authentication token. To configure this, Client provides methods to set the
|
|
|
|
token and the HTTP client. For more information, see the respective documentation
|
2016-06-26 11:04:04 +00:00
|
|
|
of SetHttpClient and SetToken, or take a look at the fluent-style companion
|
|
|
|
methods WithHttpClient and WithToken.
|
2016-06-25 10:15:58 +00:00
|
|
|
*/
|
2016-06-26 10:57:14 +00:00
|
|
|
type Client struct {
|
|
|
|
httpClient http.Client
|
2016-06-12 22:39:00 +00:00
|
|
|
|
|
|
|
// Insert an API token here if you have one. It will be sent across with all requests.
|
2016-06-26 10:57:14 +00:00
|
|
|
authToken string
|
2016-06-12 22:39:00 +00:00
|
|
|
}
|
|
|
|
|
2016-06-25 21:22:52 +00:00
|
|
|
// NewClient creates a new Client instance that wraps around the given HTTP client.
|
2016-06-25 10:15:58 +00:00
|
|
|
//
|
2016-06-26 10:57:14 +00:00
|
|
|
// A call to this method is not necessary in order to create a working instance
|
|
|
|
// of Client. `new(footballdata.Client)` works just as fine.
|
|
|
|
func NewClient(h *http.Client) *Client {
|
|
|
|
return &Client{httpClient: *h}
|
2016-06-12 22:39:00 +00:00
|
|
|
}
|
|
|
|
|
2016-06-26 10:24:59 +00:00
|
|
|
// SetToken sets the authentication token.
|
|
|
|
// Calling this method is *optional*.
|
2016-06-26 10:57:14 +00:00
|
|
|
func (c *Client) SetToken(authToken string) {
|
|
|
|
c.authToken = authToken
|
|
|
|
}
|
|
|
|
|
2016-06-26 11:04:04 +00:00
|
|
|
// WithToken sets the authentication token on a copy of the current Client
|
|
|
|
// instance.
|
|
|
|
//
|
|
|
|
// This method allows for easy fluent-style usage.
|
|
|
|
func (c Client) WithToken(authToken string) *Client {
|
|
|
|
c.authToken = authToken
|
|
|
|
return &c
|
|
|
|
}
|
|
|
|
|
2016-06-26 10:57:14 +00:00
|
|
|
// SetHttpClient sets the client that should be used to send out requests.
|
|
|
|
// Calling this method is *optional*.
|
|
|
|
func (c *Client) SetHttpClient(client *http.Client) {
|
|
|
|
if client == nil {
|
|
|
|
panic("client must not be nil")
|
|
|
|
}
|
|
|
|
c.httpClient = *client
|
2016-06-25 10:15:58 +00:00
|
|
|
}
|
|
|
|
|
2016-06-26 11:04:04 +00:00
|
|
|
// WithHttpClient sets the client that should be used to send out requests on
|
|
|
|
// a copy of the current Client instance.
|
|
|
|
//
|
|
|
|
// This method allows for easy fluent-style usage.
|
|
|
|
func (c Client) WithHttpClient(client *http.Client) *Client {
|
|
|
|
if client == nil {
|
|
|
|
panic("client must not be nil")
|
|
|
|
}
|
|
|
|
c.httpClient = *client
|
|
|
|
return &c
|
|
|
|
}
|
|
|
|
|
2016-06-26 10:57:14 +00:00
|
|
|
func (c *Client) req(path string, pathValues ...interface{}) request {
|
2016-06-12 22:39:00 +00:00
|
|
|
return request{c, fmt.Sprintf(path, pathValues...), url.Values{}}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Executes an HTTP request with given parameters and on success returns the response wrapped in a JSON decoder.
|
2016-06-26 10:57:14 +00:00
|
|
|
func (c *Client) doJson(method string, path string, values url.Values) (j *json.Decoder, meta ResponseMeta, err error) {
|
2016-06-12 22:39:00 +00:00
|
|
|
// Create request
|
|
|
|
req := &http.Request{
|
|
|
|
Method: method,
|
|
|
|
URL: resolveRelativeUrl(path, values),
|
2016-06-13 17:46:46 +00:00
|
|
|
Header: http.Header{},
|
2016-06-12 22:39:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set request headers
|
2016-06-26 10:57:14 +00:00
|
|
|
if len(c.authToken) > 0 {
|
|
|
|
req.Header.Set("X-Auth-Token", c.authToken)
|
2016-06-12 22:39:00 +00:00
|
|
|
}
|
|
|
|
req.Header.Set("X-Response-Control", "minified")
|
|
|
|
req.Header.Set("User-Agent", "go-footballdata/0.0")
|
|
|
|
|
|
|
|
// Execute request
|
2016-06-25 10:15:58 +00:00
|
|
|
resp, err := c.httpClient.Do(req)
|
2016-06-12 22:39:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2016-06-13 17:46:27 +00:00
|
|
|
defer resp.Body.Close()
|
2016-06-12 22:39:00 +00:00
|
|
|
|
|
|
|
// Save metadata from headers
|
|
|
|
meta = responseMetaFromHeaders(resp.Header)
|
|
|
|
|
2016-06-13 17:46:27 +00:00
|
|
|
// Expect the request to be successful, otherwise throw an error
|
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
err = errors.New(resp.Status)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-06-12 22:39:00 +00:00
|
|
|
// Download to buffer to allow passing back a fully prepared decoder
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
io.Copy(buf, resp.Body)
|
|
|
|
|
|
|
|
// Wrap JSON decoder around buffered data
|
|
|
|
j = json.NewDecoder(buf)
|
|
|
|
return
|
|
|
|
}
|