diff --git a/github/github.go b/github/github.go index 49f218c..5d0b791 100644 --- a/github/github.go +++ b/github/github.go @@ -53,12 +53,16 @@ import ( "io/ioutil" "net/http" "net/url" + "strconv" ) const ( libraryVersion = "0.1" defaultBaseURL = "https://api.github.com/" userAgent = "go-github/" + libraryVersion + + headerRateLimit = "X-RateLimit-Limit" + headerRateRemaining = "X-RateLimit-Remaining" ) // A Client manages communication with the GitHub API. @@ -74,6 +78,12 @@ type Client struct { // User agent used when communicating with the GitHub API. UserAgent string + // Rate specifies the current rate limit for the client as determined by the + // most recent API call. If the client is used in a multi-user application, + // this rate may not always be up-to-date. Call RateLimit() to check the + // current rate. + Rate Rate + // Services used for talking to different parts of the API Issues *IssuesService @@ -150,6 +160,14 @@ func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) { defer resp.Body.Close() + // update rate limit + if limit := resp.Header.Get(headerRateLimit); limit != "" { + c.Rate.Limit, _ = strconv.Atoi(limit) + } + if remaining := resp.Header.Get(headerRateRemaining); remaining != "" { + c.Rate.Remaining, _ = strconv.Atoi(remaining) + } + err = CheckResponse(resp) if err != nil { return resp, err diff --git a/github/github_test.go b/github/github_test.go index 8772084..fc3b914 100644 --- a/github/github_test.go +++ b/github/github_test.go @@ -193,6 +193,58 @@ func TestDo_redirectLoop(t *testing.T) { } } +func TestDo_rateLimit(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Header().Add(headerRateLimit, "60") + w.Header().Add(headerRateRemaining, "59") + }) + + var want int + + if want = 0; client.Rate.Limit != want { + t.Errorf("Client rate limit = %v, want %v", client.Rate.Limit, want) + } + if want = 0; client.Rate.Limit != want { + t.Errorf("Client rate remaining, got %v", client.Rate.Remaining, want) + } + + req, _ := client.NewRequest("GET", "/", nil) + client.Do(req, nil) + + if want = 60; client.Rate.Limit != want { + t.Errorf("Client rate limit = %v, want %v", client.Rate.Limit, want) + } + if want = 59; client.Rate.Remaining != want { + t.Errorf("Client rate remaining = %v, want %v", client.Rate.Remaining, want) + } +} + +func TestDo_rateLimit_errorResponse(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Header().Add(headerRateLimit, "60") + w.Header().Add(headerRateRemaining, "59") + http.Error(w, "Bad Request", 400) + }) + + var want int + + req, _ := client.NewRequest("GET", "/", nil) + client.Do(req, nil) + + if want = 60; client.Rate.Limit != want { + t.Errorf("Client rate limit = %v, want %v", client.Rate.Limit, want) + } + if want = 59; client.Rate.Remaining != want { + t.Errorf("Client rate remaining = %v, want %v", client.Rate.Remaining, want) + } +} + func TestCheckResponse(t *testing.T) { res := &http.Response{ Request: &http.Request{},