Skip to content

Commit e36f188

Browse files
committed
Add list notes
1 parent b6afc6e commit e36f188

File tree

4 files changed

+90
-57
lines changed

4 files changed

+90
-57
lines changed

errors.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package habitify
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
)
7+
8+
type ErrPreconditionFailed struct {
9+
msg string
10+
}
11+
12+
func (e *ErrPreconditionFailed) Error() string {
13+
return e.msg
14+
}
15+
16+
func newError(statusCode int, msg string) error {
17+
switch statusCode {
18+
case http.StatusPreconditionFailed:
19+
return &ErrPreconditionFailed{msg: msg}
20+
}
21+
return fmt.Errorf("unknown error: %s", msg)
22+
}

habitify.go

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bytes"
55
"context"
66
"encoding/json"
7-
"errors"
87
"fmt"
98
"io"
109
"io/ioutil"
@@ -16,8 +15,16 @@ const DefaultEndpoint = "https://api.habitify.me"
1615

1716
const (
1817
urlHabits = "/habits"
18+
urlNotes = "/notes"
1919
)
2020

21+
type apiResponse struct {
22+
Message string `json:"message"`
23+
Version string `json:"version"`
24+
Status bool `json:"status"`
25+
Data json.RawMessage `json:"data"`
26+
}
27+
2128
// Client is a client for Habitify API.
2229
type Client struct {
2330
httpClient *http.Client
@@ -75,53 +82,48 @@ func (resp *httpResponse) Close() {
7582
_ = resp.Body.Close()
7683
}
7784

78-
func (c *Client) do(ctx context.Context, method, path string, body io.Reader) (*httpResponse, error) {
85+
func (c *Client) do(ctx context.Context, method, path string, body io.Reader, data interface{}) error {
7986
req, err := http.NewRequestWithContext(ctx, method, c.endpoint+path, body)
8087

8188
if err != nil {
82-
return nil, err
89+
return err
8390
}
8491

8592
req.Header.Add("Authorization", c.apiKey)
8693
req.Header.Add("Content-Type", "application/json; charset=utf8")
8794

8895
resp, err := c.httpClient.Do(req)
8996
if err != nil {
90-
return nil, err
97+
return err
9198
}
99+
defer resp.Body.Close()
92100

93-
switch resp.StatusCode {
94-
case http.StatusBadRequest:
95-
return nil, errors.New("client has issues an invalid request")
96-
case http.StatusUnauthorized:
97-
return nil, errors.New("authorization for the API is required but the request has not been authenticated")
98-
case http.StatusForbidden:
99-
return nil, errors.New("the request has been authenticated but does not have permission or the resource is not found")
100-
case http.StatusNotAcceptable:
101-
return nil, errors.New("the client has requestd a MIM typ via the Accept header for a value not supported by the server")
102-
case http.StatusUnsupportedMediaType:
103-
return nil, errors.New("the client has defined a Content-Type header that is not supported by the server")
104-
case http.StatusUnprocessableEntity:
105-
return nil, errors.New("the client has made a valid request but the server cannot process it")
106-
case http.StatusTooManyRequests:
107-
return nil, errors.New("the client has exceeded the number of requests allowed for a givn time window")
108-
case http.StatusInternalServerError:
109-
return nil, errors.New("an unexpected error on the server has occurred")
101+
httpResp := &httpResponse{Response: resp}
102+
var apiResp apiResponse
103+
if err := httpResp.DecodeJSON(&apiResp); err != nil {
104+
return err
105+
}
106+
if !apiResp.Status {
107+
return newError(resp.StatusCode, apiResp.Message)
110108
}
111109

112-
return &httpResponse{Response: resp}, nil
110+
if err := json.Unmarshal(apiResp.Data, data); err != nil {
111+
return fmt.Errorf("decoding JSON data: %w", err)
112+
}
113+
114+
return nil
113115
}
114116

115-
func (c *Client) get(ctx context.Context, path string) (*httpResponse, error) {
116-
return c.do(ctx, http.MethodGet, path, nil)
117+
func (c *Client) get(ctx context.Context, path string, data interface{}) error {
118+
return c.do(ctx, http.MethodGet, path, nil, data)
117119
}
118120

119-
func (c *Client) post(ctx context.Context, path string, body interface{}) (*httpResponse, error) {
121+
func (c *Client) post(ctx context.Context, path string, body interface{}) error {
120122
var buf bytes.Buffer
121123

122124
if err := json.NewEncoder(&buf).Encode(body); err != nil {
123-
return nil, err
125+
return err
124126
}
125127

126-
return c.do(ctx, http.MethodPost, path, &buf)
128+
return c.do(ctx, http.MethodPost, path, &buf, nil)
127129
}

habits.go

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,6 @@ import (
66
"time"
77
)
88

9-
type getHabitResp struct {
10-
Message string `json:"message"`
11-
Habit *Habit `json:"data"`
12-
Version string `json:"version"`
13-
Status bool `json:"status"`
14-
}
15-
16-
type listHabitsResp struct {
17-
Message string `json:"message"`
18-
Habits []*Habit `json:"data"`
19-
Version string `json:"version"`
20-
Status bool `json:"status"`
21-
}
22-
239
type Habit struct {
2410
ID string `json:"id"`
2511
Name string `json:"name"`
@@ -49,31 +35,21 @@ type Habit struct {
4935
}
5036

5137
func (c *Client) GetHabit(ctx context.Context, id string) (*Habit, error) {
52-
resp, err := c.get(ctx, fmt.Sprintf("%s/%s", urlHabits, id))
38+
var habit Habit
39+
err := c.get(ctx, fmt.Sprintf("%s/%s", urlHabits, id), &habit)
5340
if err != nil {
5441
return nil, err
5542
}
56-
defer resp.Close()
57-
58-
var response getHabitResp
59-
if err := resp.DecodeJSON(&response); err != nil {
60-
return nil, err
61-
}
6243

63-
return response.Habit, nil
44+
return &habit, nil
6445
}
6546

6647
func (c *Client) ListHabits(ctx context.Context) ([]*Habit, error) {
67-
resp, err := c.get(ctx, urlHabits)
48+
var habits []*Habit
49+
err := c.get(ctx, urlHabits, &habits)
6850
if err != nil {
6951
return nil, err
7052
}
71-
defer resp.Close()
72-
73-
var response listHabitsResp
74-
if err := resp.DecodeJSON(&response); err != nil {
75-
return nil, err
76-
}
7753

78-
return response.Habits, nil
54+
return habits, nil
7955
}

notes.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package habitify
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
"time"
8+
)
9+
10+
const dateFormat = "2006-01-02T15:04:05-07:00"
11+
12+
type Note struct {
13+
ID string `json:"id"`
14+
Content string `json:"content"`
15+
CreatedDate string `json:"created_date"`
16+
ImageURL interface{} `json:"image_url"`
17+
NoteType int `json:"note_type"`
18+
HabitID string `json:"habit_id"`
19+
}
20+
21+
func (c *Client) ListNotes(ctx context.Context, habitID string, from, to time.Time) ([]*Note, error) {
22+
var notes []*Note
23+
err := c.get(ctx, fmt.Sprintf("%s/%s?from=%s&to=%s", urlNotes, habitID, formatTime(from), formatTime(to)), &notes)
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
return notes, nil
29+
}
30+
31+
func formatTime(t time.Time) string {
32+
return url.QueryEscape(t.Format(dateFormat))
33+
}

0 commit comments

Comments
 (0)