func (g *GitHub) httpPost(uri string, extraHeaders map[string]string, content *bytes.Buffer) (resp *http.Response, err error) {
	url := fmt.Sprintf("%s%s", GitHubUrl, uri)
	request, err := http.NewRequest("POST", url, content)
	if err != nil {
		return
	}
	if extraHeaders != nil {
		for h, v := range extraHeaders {
			request.Header.Set(h, v)
		}
	}
	request.Header.Set("Content-Type", "application/json; charset=utf-8")
	resp, err = g.call(request)
	return
}
Makes an HTTP POST request to the specified GitHub endpoint.
package gothub
import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)
const (
	GitHubUrl       string = "https://api.github.com"
	DefaultPageSize int    = 30
	AcceptHeader    string = "application/vnd.github.beta+json"
)
var (
	ErrRateLimitReached = errors.New("Rate limit reached")
	ErrNoJSON           = errors.New("GitHub did not return a JSON response")
)
type GitHub struct {
	httpClient         *http.Client
	Authorization      string
	RateLimit          int
	RateLimitRemaining int
}
func hashAuth(u, p string) string {
	var a = fmt.Sprintf("%s:%s", u, p)
	return base64.StdEncoding.EncodeToString([]byte(a))
}
func Guest() (*GitHub, error) {
	request, err := http.NewRequest("GET", GitHubUrl, nil)
	if err != nil {
		return nil, err
	}
	client := &http.Client{}
	response, err := client.Do(request)
	if response.StatusCode == http.StatusOK {
		ratelimit, err := strconv.Atoi(response.Header.Get("X-RateLimit-Limit"))
		if err != nil {
			return nil, err
		}
		remaining, err := strconv.Atoi(response.Header.Get("X-RateLimit-Remaining"))
		if err != nil {
			return nil, err
		}
		return &GitHub{httpClient: client, RateLimit: ratelimit, RateLimitRemaining: remaining}, nil
	}
	return nil, err
}
func BasicLogin(username, password string) (*GitHub, error) {
	authorization := fmt.Sprintf("Basic %s", hashAuth(username, password))
	request, err := http.NewRequest("GET", GitHubUrl, nil)
	if err != nil {
		return nil, err
	}
	request.Header.Set("Authorization", authorization)
	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		return nil, err
	}
	if response.StatusCode == http.StatusOK {
		ratelimit, err := strconv.Atoi(response.Header.Get("X-RateLimit-Limit"))
		if err != nil {
			return nil, err
		}
		remaining, err := strconv.Atoi(response.Header.Get("X-RateLimit-Remaining"))
		if err != nil {
			return nil, err
		}
		return &GitHub{httpClient: client, Authorization: authorization,
			RateLimit: ratelimit, RateLimitRemaining: remaining}, nil
	}
	e := "Authorization failed with HTTP code: %d"
	return nil, errors.New(fmt.Sprintf(e, response.StatusCode))
}
func (g *GitHub) Do(v interface{}, method string, uriParts ...string) (err error) {
	if g.RateLimitRemaining == 0 {
		err = ErrRateLimitReached
		return
	}
	url := fmt.Sprintf("%s/%s", GitHubUrl, strings.Join(uriParts, "/"))
	var request *http.Request
	request, err = http.NewRequest(method, url, nil)
	if err != nil {
		return
	}
	request.Header.Set("Authorization", g.Authorization)
	request.Header.Set("Accept", AcceptHeader)
	var response *http.Response
	response, err = g.httpClient.Do(request)
	if err != nil {
		return
	}
	g.updateRates(response)
	switch strings.ToUpper(method) {
	case "GET":
		switch response.StatusCode {
		case http.StatusNoContent, http.StatusOK:
			if response.ContentLength == 0 && v == nil {
				return
			}
		default:
			err = errors.New(fmt.Sprintf("GitHub API responded with HTTP %d", response.StatusCode))
			return
		}
	}
	if v != nil {
		switch response.Header.Get("Content-Type") {
		case "application/json":
			fallthrough
		case "application/json; charset=utf-8":
			var body []byte
			body, err = ioutil.ReadAll(response.Body)
			if err != nil {
				return
			}
			err = json.Unmarshal(body, v)
		default:
			err = ErrNoJSON
		}
	}
	return
}
func (g *GitHub) updateRates(r *http.Response) (err error) {
	limit, err := strconv.Atoi(r.Header.Get("X-RateLimit-Limit"))
	if err != nil {
		return
	}
	g.RateLimit = limit
	remaining, err := strconv.Atoi(r.Header.Get("X-RateLimit-Remaining"))
	if err != nil {
		return
	}
	g.RateLimitRemaining = remaining
	return
}
func call(g *GitHub, method, uri string) (response *http.Response, err error) {
	if g.RateLimitRemaining == 0 {
		err = ErrRateLimitReached
		return
	}
	url := fmt.Sprintf("%s%s", GitHubUrl, uri)
	request, err := http.NewRequest(method, url, nil)
	if err != nil {
		return
	}
	if g.Authorization != "" {
		request.Header.Set("Authorization", g.Authorization)
	}
	request.Header.Set("Accept", AcceptHeader)
	response, err = g.httpClient.Do(request)
	if err != nil {
		return
	}
	g.updateRates(response)
	switch method {
	case "GET":
		if response.StatusCode != http.StatusOK {
			e := "GitHub API responded with HTTP %d"
			err = errors.New(fmt.Sprintf(e, response.StatusCode))
		}
	case "POST":
		switch response.StatusCode {
		case http.StatusCreated:
			return
		}
	case "DELETE":
		switch response.StatusCode {
		case http.StatusNoContent:
			return
		}
	}
	return
}
func (g *GitHub) callGithubApi(method, uri string, rs interface{}) error {
	response, err := call(g, method, uri)
	if err != nil {
		return err
	}
	switch response.Header.Get("Content-Type") {
	case "application/json":
		fallthrough
	case "application/json; charset=utf-8":
		var js []byte
		js, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return err
		} else {
			err = json.Unmarshal(js, rs)
		}
	default:
		err = ErrNoJSON
	}
	return err
}
type unprocessableEntityError struct {
	Resource string `json:"resource"`
	Field    string `json:"field"`
	Code     string `json:"code"`
}
type unprocessableEntity struct {
	Message string                     `json:"message"`
	Errors  []unprocessableEntityError `json:"errors"`
}
func (g *GitHub) call(req *http.Request) (response *http.Response, err error) {
	if g.RateLimitRemaining == 0 {
		err = ErrRateLimitReached
		return
	}
	req.Header.Set("Authorization", g.Authorization)
	response, err = g.httpClient.Do(req)
	g.updateRates(response)
	if response.StatusCode != 422 {
		return
	}
	body, err := ioutil.ReadAll(response.Body)
	var uerror error
	if err == nil {
		var unprocessable unprocessableEntity
		err = json.Unmarshal(body, &unprocessable)
		if err != nil {
			return
		}
		e := "%s: %+v"
		uerror = errors.New(fmt.Sprintf(e, unprocessable.Message,
			unprocessable.Errors))
	}
	if uerror != nil {
		err = uerror
	}
	return
}
func (g *GitHub) httpGet(uri string, extraHeaders map[string]string) (resp *http.Response, err error) {
	url := fmt.Sprintf("%s%s", GitHubUrl, uri)
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return
	}
	if extraHeaders != nil {
		for k, v := range extraHeaders {
			request.Header.Set(k, v)
		}
	}
	resp, err = g.call(request)
	return
}