Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add context support, ErrUnauthorized and Doer interface for http.Client #4

Merged
merged 13 commits into from
Oct 15, 2016
Merged
53 changes: 27 additions & 26 deletions asana/asana.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package asana

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -169,82 +170,82 @@ func NewClient(doer Doer) *Client {
return client
}

func (c *Client) ListWorkspaces() ([]Workspace, error) {
func (c *Client) ListWorkspaces(ctx context.Context) ([]Workspace, error) {
workspaces := new([]Workspace)
err := c.Request("workspaces", nil, workspaces)
err := c.Request(ctx, "workspaces", nil, workspaces)
return *workspaces, err
}

func (c *Client) ListUsers(opt *Filter) ([]User, error) {
func (c *Client) ListUsers(ctx context.Context, opt *Filter) ([]User, error) {
users := new([]User)
err := c.Request("users", opt, users)
err := c.Request(ctx, "users", opt, users)
return *users, err
}

func (c *Client) ListProjects(opt *Filter) ([]Project, error) {
func (c *Client) ListProjects(ctx context.Context, opt *Filter) ([]Project, error) {
projects := new([]Project)
err := c.Request("projects", opt, projects)
err := c.Request(ctx, "projects", opt, projects)
return *projects, err
}

func (c *Client) ListTasks(opt *Filter) ([]Task, error) {
func (c *Client) ListTasks(ctx context.Context, opt *Filter) ([]Task, error) {
tasks := new([]Task)
err := c.Request("tasks", opt, tasks)
err := c.Request(ctx, "tasks", opt, tasks)
return *tasks, err
}

func (c *Client) GetTask(id int64, opt *Filter) (Task, error) {
func (c *Client) GetTask(ctx context.Context, id int64, opt *Filter) (Task, error) {
task := new(Task)
err := c.Request(fmt.Sprintf("tasks/%d", id), opt, task)
err := c.Request(ctx, fmt.Sprintf("tasks/%d", id), opt, task)
return *task, err
}

// UpdateTask updates a task.
//
// https://asana.com/developers/api-reference/tasks#update
func (c *Client) UpdateTask(id int64, tu TaskUpdate, opt *Filter) (Task, error) {
func (c *Client) UpdateTask(ctx context.Context, id int64, tu TaskUpdate, opt *Filter) (Task, error) {
task := new(Task)
err := c.request("PUT", fmt.Sprintf("tasks/%d", id), tu, opt, task)
err := c.request(ctx, "PUT", fmt.Sprintf("tasks/%d", id), tu, opt, task)
return *task, err
}

func (c *Client) ListProjectTasks(projectID int64, opt *Filter) ([]Task, error) {
func (c *Client) ListProjectTasks(ctx context.Context, projectID int64, opt *Filter) ([]Task, error) {
tasks := new([]Task)
err := c.Request(fmt.Sprintf("projects/%d/tasks", projectID), opt, tasks)
err := c.Request(ctx, fmt.Sprintf("projects/%d/tasks", projectID), opt, tasks)
return *tasks, err
}

func (c *Client) ListTaskStories(taskID int64, opt *Filter) ([]Story, error) {
func (c *Client) ListTaskStories(ctx context.Context, taskID int64, opt *Filter) ([]Story, error) {
stories := new([]Story)
err := c.Request(fmt.Sprintf("tasks/%d/stories", taskID), opt, stories)
err := c.Request(ctx, fmt.Sprintf("tasks/%d/stories", taskID), opt, stories)
return *stories, err
}

func (c *Client) ListTags(opt *Filter) ([]Tag, error) {
func (c *Client) ListTags(ctx context.Context, opt *Filter) ([]Tag, error) {
tags := new([]Tag)
err := c.Request("tags", opt, tags)
err := c.Request(ctx, "tags", opt, tags)
return *tags, err
}

func (c *Client) GetAuthenticatedUser(opt *Filter) (User, error) {
func (c *Client) GetAuthenticatedUser(ctx context.Context, opt *Filter) (User, error) {
user := new(User)
err := c.Request("users/me", opt, user)
err := c.Request(ctx, "users/me", opt, user)
return *user, err
}

func (c *Client) GetUserByID(id int64, opt *Filter) (User, error) {
func (c *Client) GetUserByID(ctx context.Context, id int64, opt *Filter) (User, error) {
user := new(User)
err := c.Request(fmt.Sprintf("users/%d", id), opt, user)
err := c.Request(ctx, fmt.Sprintf("users/%d", id), opt, user)
return *user, err
}

func (c *Client) Request(path string, opt *Filter, v interface{}) error {
return c.request("GET", path, nil, opt, v)
func (c *Client) Request(ctx context.Context, path string, opt *Filter, v interface{}) error {
return c.request(ctx, "GET", path, nil, opt, v)
}

// request makes a request to Asana API, using method, at path, sending data with opt filter.
// The response is populated into v, and any error is returned.
func (c *Client) request(method string, path string, data interface{}, opt *Filter, v interface{}) error {
func (c *Client) request(ctx context.Context, method string, path string, data interface{}, opt *Filter, v interface{}) error {
if opt == nil {
opt = &Filter{}
}
Expand Down Expand Up @@ -280,7 +281,7 @@ func (c *Client) request(method string, path string, data interface{}, opt *Filt
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("User-Agent", c.UserAgent)
resp, err := c.doer.Do(req)
resp, err := c.doer.Do(req.WithContext(ctx))
if err != nil {
return err
}
Expand Down
16 changes: 9 additions & 7 deletions asana/asana_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package asana

import (
"context"
"fmt"
"io/ioutil"
"net/http"
Expand All @@ -14,6 +15,7 @@ var (
client *Client
mux *http.ServeMux
server *httptest.Server
ctx = context.Background()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's a test, but still, this isn't saving much typing. Instead of this variable here, just use context.Background() directly at the call sites. E.g.:

workspaces, err := client.ListWorkspaces(context.Background())
...
users, err := client.ListUsers(context.Background(), nil)
...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to write 3 letters instead of context.Background() in tests, but it's not a big deal. I remove this global variable and put context.Background().

)

func setup() {
Expand Down Expand Up @@ -57,7 +59,7 @@ func TestListWorkspaces(t *testing.T) {
]}`)
})

workspaces, err := client.ListWorkspaces()
workspaces, err := client.ListWorkspaces(ctx)
if err != nil {
t.Errorf("ListWorkspaces returned error: %v", err)
}
Expand All @@ -83,7 +85,7 @@ func TestListUsers(t *testing.T) {
]}`)
})

users, err := client.ListUsers(nil)
users, err := client.ListUsers(ctx, nil)
if err != nil {
t.Errorf("ListUsers returned error: %v", err)
}
Expand All @@ -109,7 +111,7 @@ func TestListProjects(t *testing.T) {
]}`)
})

projects, err := client.ListProjects(nil)
projects, err := client.ListProjects(ctx, nil)
if err != nil {
t.Errorf("ListProjects returned error: %v", err)
}
Expand All @@ -135,7 +137,7 @@ func TestListTasks(t *testing.T) {
]}`)
})

tasks, err := client.ListTasks(nil)
tasks, err := client.ListTasks(ctx, nil)
if err != nil {
t.Errorf("ListTasks returned error: %v", err)
}
Expand Down Expand Up @@ -178,7 +180,7 @@ func TestUpdateTask(t *testing.T) {
// to store v and returns a pointer to it.
String := func(v string) *string { return &v }

task, err := client.UpdateTask(1, TaskUpdate{Notes: String("updated notes")}, nil)
task, err := client.UpdateTask(ctx, 1, TaskUpdate{Notes: String("updated notes")}, nil)
if err != nil {
t.Errorf("UpdateTask returned error: %v", err)
}
Expand All @@ -200,7 +202,7 @@ func TestListTags(t *testing.T) {
]}`)
})

tags, err := client.ListTags(nil)
tags, err := client.ListTags(ctx, nil)
if err != nil {
t.Errorf("ListTags returned error: %v", err)
}
Expand All @@ -223,7 +225,7 @@ func TestUnauthorized(t *testing.T) {
w.WriteHeader(http.StatusUnauthorized)
})

_, err := client.ListTags(nil)
_, err := client.ListTags(ctx, nil)
if err != ErrUnauthorized {
t.Errorf("Unexpected err %v", err)
}
Expand Down