Go client for the Write.as API https://developers.write.as
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
3.2 KiB

  1. // Package writeas provides the binding for the Write.as API
  2. package writeas
  3. import (
  4. "bytes"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "github.com/writeas/impart"
  9. "io"
  10. "net/http"
  11. "time"
  12. )
  13. const (
  14. apiURL = "https://write.as/api"
  15. )
  16. // Client is used to interact with the Write.as API. It can be used to make
  17. // authenticated or unauthenticated calls.
  18. type Client struct {
  19. baseURL string
  20. // Access token for the user making requests.
  21. token string
  22. // Client making requests to the API
  23. client *http.Client
  24. }
  25. // defaultHTTPTimeout is the default http.Client timeout.
  26. const defaultHTTPTimeout = 10 * time.Second
  27. // NewClient creates a new API client. By default, all requests are made
  28. // unauthenticated. To optionally make authenticated requests, call `SetToken`.
  29. //
  30. // c := writeas.NewClient()
  31. // c.SetToken("00000000-0000-0000-0000-000000000000")
  32. func NewClient() *Client {
  33. return &Client{
  34. client: &http.Client{Timeout: defaultHTTPTimeout},
  35. baseURL: apiURL,
  36. }
  37. }
  38. // SetToken sets the user token for all future Client requests. Setting this to
  39. // an empty string will change back to unauthenticated requests.
  40. func (c *Client) SetToken(token string) {
  41. c.token = token
  42. }
  43. func (c *Client) get(path string, r interface{}) (*impart.Envelope, error) {
  44. method := "GET"
  45. if method != "GET" && method != "HEAD" {
  46. return nil, errors.New(fmt.Sprintf("Method %s not currently supported by library (only HEAD and GET).\n", method))
  47. }
  48. return c.request(method, path, nil, r)
  49. }
  50. func (c *Client) post(path string, data, r interface{}) (*impart.Envelope, error) {
  51. b := new(bytes.Buffer)
  52. json.NewEncoder(b).Encode(data)
  53. return c.request("POST", path, b, r)
  54. }
  55. func (c *Client) put(path string, data, r interface{}) (*impart.Envelope, error) {
  56. b := new(bytes.Buffer)
  57. json.NewEncoder(b).Encode(data)
  58. return c.request("PUT", path, b, r)
  59. }
  60. func (c *Client) delete(path string, data map[string]string) (*impart.Envelope, error) {
  61. r, err := c.buildRequest("DELETE", path, nil)
  62. if err != nil {
  63. return nil, err
  64. }
  65. q := r.URL.Query()
  66. for k, v := range data {
  67. q.Add(k, v)
  68. }
  69. r.URL.RawQuery = q.Encode()
  70. return c.doRequest(r, nil)
  71. }
  72. func (c *Client) request(method, path string, data io.Reader, result interface{}) (*impart.Envelope, error) {
  73. r, err := c.buildRequest(method, path, data)
  74. if err != nil {
  75. return nil, err
  76. }
  77. return c.doRequest(r, result)
  78. }
  79. func (c *Client) buildRequest(method, path string, data io.Reader) (*http.Request, error) {
  80. url := fmt.Sprintf("%s%s", c.baseURL, path)
  81. r, err := http.NewRequest(method, url, data)
  82. if err != nil {
  83. return nil, fmt.Errorf("Create request: %v", err)
  84. }
  85. c.prepareRequest(r)
  86. return r, nil
  87. }
  88. func (c *Client) doRequest(r *http.Request, result interface{}) (*impart.Envelope, error) {
  89. resp, err := c.client.Do(r)
  90. if err != nil {
  91. return nil, fmt.Errorf("Request: %v", err)
  92. }
  93. defer resp.Body.Close()
  94. env := &impart.Envelope{
  95. Code: resp.StatusCode,
  96. }
  97. if result != nil {
  98. env.Data = result
  99. err = json.NewDecoder(resp.Body).Decode(&env)
  100. if err != nil {
  101. return nil, err
  102. }
  103. }
  104. return env, nil
  105. }
  106. func (c *Client) prepareRequest(r *http.Request) {
  107. r.Header.Add("User-Agent", "go-writeas v1")
  108. r.Header.Add("Content-Type", "application/json")
  109. if c.token != "" {
  110. r.Header.Add("Authorization", "Token "+c.token)
  111. }
  112. }