Skip to content

Commit

Permalink
Merge pull request digitalocean#4 from digitalocean/v0.3
Browse files Browse the repository at this point in the history
Update to current API spec
  • Loading branch information
bryanl committed Sep 9, 2014
2 parents 6a5163c + 96accbf commit db6b5a6
Show file tree
Hide file tree
Showing 20 changed files with 989 additions and 246 deletions.
76 changes: 54 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# GODO
# Godo

Godo is a Go client library for accessing the DigitalOcean V2 API.

You can view the client API docs here: [http://godoc.org/github.com/digitalocean/godo](http://godoc.org/github.com/digitalocean/godo)

You can view Digital Ocean API docs here: [https://developers.digitalocean.com/v2/](https://developers.digitalocean.com/v2/)


## Usage

```go
import "github.com/digitaloceancloud/godo"
import "github.com/digitalocean/godo"
```

Create a new DigitalOcean client, then use the exposed services to
Expand All @@ -32,37 +37,64 @@ client := godo.NewClient(t.Client())

## Examples

[Digital Ocean API Documentation](https://developers.digitalocean.com/v2/)


To list all Droplets your account has access to:

```go
droplets, _, err := client.Droplet.List()
if err != nil {
fmt.Printf("error: %v\n\n", err)
return err
} else {
fmt.Printf("%v\n\n", godo.Stringify(droplets))
}
```

To create a new Droplet:

```go
dropletName := "super-cool-droplet"

createRequest := &godo.DropletCreateRequest{
Name: godo.String(dropletName),
Region: godo.String("nyc2"),
Size: godo.String("512mb"),
Image: godo.Int(3240036), // ubuntu 14.04 64bit
Name: godo.String(dropletName),
Region: godo.String("nyc2"),
Size: godo.String("512mb"),
Image: godo.Int(3240036), // ubuntu 14.04 64bit
}

newDroplet, _, err := client.Droplet.Create(createRequest)

if err != nil {
fmt.Printf("Something bad happened: %s\n\n", err)
return err
fmt.Printf("Something bad happened: %s\n\n", err)
return err
}
```

### Pagination

If a list of items is paginated by the API, you must request pages individually. For example, to fetch all Droplets:

```go
func DropletList(client *godo.Client) ([]godo.Droplet, error) {
// create a list to hold our droplets
list := []godo.Droplet{}

// create options. initially, these will be blank
opt := &godo.ListOptions{}
for {
droplets, resp, err := client.Droplets.List(opt)
if err != nil {
return err
}

// append the current page's droplets to our list
for _, d := range droplets {
list = append(list, d)
}

// if we are at the last page, break out the for loop
if resp.Links.IsLastPage() {
break
}

page, err := resp.Links.CurrentPage()
if err != nil {
return err
}

// set the page we want for the next request
opt.Page = page + 1
}

return nil
}

```
12 changes: 10 additions & 2 deletions action.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const (
// ActionsService handles communction with action related methods of the
// DigitalOcean API: https://developers.digitalocean.com/#actions
type ActionsService interface {
List() ([]Action, *Response, error)
List(*ListOptions) ([]Action, *Response, error)
Get(int) (*Action, *Response, error)
}

Expand All @@ -27,6 +27,7 @@ type ActionsServiceOp struct {

type actionsRoot struct {
Actions []Action `json:"actions"`
Links *Links `json:"links"`
}

type actionRoot struct {
Expand All @@ -45,8 +46,12 @@ type Action struct {
}

// List all actions
func (s *ActionsServiceOp) List() ([]Action, *Response, error) {
func (s *ActionsServiceOp) List(opt *ListOptions) ([]Action, *Response, error) {
path := actionsBasePath
path, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
Expand All @@ -58,6 +63,9 @@ func (s *ActionsServiceOp) List() ([]Action, *Response, error) {
if err != nil {
return nil, resp, err
}
if l := root.Links; l != nil {
resp.Links = l
}

return root.Actions, resp, err
}
Expand Down
50 changes: 49 additions & 1 deletion action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestAction_List(t *testing.T) {
testMethod(t, r, "GET")
})

actions, _, err := client.Actions.List()
actions, _, err := client.Actions.List(nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
Expand All @@ -33,6 +33,54 @@ func TestAction_List(t *testing.T) {
}
}

func TestAction_ListActionMultiplePages(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/v2/actions", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{"actions": [{"id":1},{"id":2}], "links":{"pages":{"next":"http://example.com/v2/droplets/?page=2"}}}`)
testMethod(t, r, "GET")
})

_, resp, err := client.Actions.List(nil)
if err != nil {
t.Fatal(nil)
}

checkCurrentPage(t, resp, 1)
}

func TestAction_RetrievePageByNumber(t *testing.T) {
setup()
defer teardown()

jBlob := `
{
"actions": [{"id":1},{"id":2}],
"links":{
"pages":{
"next":"http://example.com/v2/actions/?page=3",
"prev":"http://example.com/v2/actions/?page=1",
"last":"http://example.com/v2/actions/?page=3",
"first":"http://example.com/v2/actions/?page=1"
}
}
}`

mux.HandleFunc("/v2/actions", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, jBlob)
})

opt := &ListOptions{Page: 2}
_, resp, err := client.Actions.List(opt)
if err != nil {
t.Fatal(err)
}

checkCurrentPage(t, resp, 2)
}

func TestAction_Get(t *testing.T) {
setup()
defer teardown()
Expand Down
136 changes: 121 additions & 15 deletions domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ const domainsBasePath = "v2/domains"
// See: https://developers.digitalocean.com/#domains and
// https://developers.digitalocean.com/#domain-records
type DomainsService interface {
Records(string, *DomainRecordsOptions) ([]DomainRecord, *Response, error)
List(*ListOptions) ([]Domain, *Response, error)
Get(string) (*DomainRoot, *Response, error)
Create(*DomainCreateRequest) (*DomainRoot, *Response, error)
Delete(string) (*Response, error)

Records(string, *ListOptions) ([]DomainRecord, *Response, error)
Record(string, int) (*DomainRecord, *Response, error)
DeleteRecord(string, int) (*Response, error)
EditRecord(string, int, *DomainRecordEditRequest) (*DomainRecord, *Response, error)
Expand All @@ -21,6 +26,29 @@ type DomainsServiceOp struct {
client *Client
}

// Domain represents a Digital Ocean domain
type Domain struct {
Name string `json:"name"`
TTL int `json:"ttl"`
ZoneFile string `json:"zone_file"`
}

// DomainRoot represents a response from the Digital Ocean API
type DomainRoot struct {
Domain *Domain `json:"domain"`
}

type domainsRoot struct {
Domains []Domain `json:"domains"`
Links *Links `json:"links"`
}

// DomainCreateRequest respresents a request to create a domain.
type DomainCreateRequest struct {
Name string `json:"name"`
IPAddress string `json:"ip_address"`
}

// DomainRecordRoot is the root of an individual Domain Record response
type DomainRecordRoot struct {
DomainRecord *DomainRecord `json:"domain_record"`
Expand All @@ -29,6 +57,7 @@ type DomainRecordRoot struct {
// DomainRecordsRoot is the root of a group of Domain Record responses
type DomainRecordsRoot struct {
DomainRecords []DomainRecord `json:"domain_records"`
Links *Links `json:"links"`
}

// DomainRecord represents a DigitalOcean DomainRecord
Expand All @@ -42,16 +71,6 @@ type DomainRecord struct {
Weight int `json:"weight,omitempty"`
}

// DomainRecordsOptions are options for DomainRecords
type DomainRecordsOptions struct {
ListOptions
}

// Converts a DomainRecord to a string.
func (d DomainRecord) String() string {
return Stringify(d)
}

// DomainRecordEditRequest represents a request to update a domain record.
type DomainRecordEditRequest struct {
Type string `json:"type,omitempty"`
Expand All @@ -62,13 +81,97 @@ type DomainRecordEditRequest struct {
Weight int `json:"weight,omitempty"`
}

func (d Domain) String() string {
return Stringify(d)
}

// List all domains
func (s DomainsServiceOp) List(opt *ListOptions) ([]Domain, *Response, error) {
path := domainsBasePath
path, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}

root := new(domainsRoot)
resp, err := s.client.Do(req, root)
if err != nil {
return nil, resp, err
}
if l := root.Links; l != nil {
resp.Links = l
}

return root.Domains, resp, err
}

// Get individual domain
func (s *DomainsServiceOp) Get(name string) (*DomainRoot, *Response, error) {
path := fmt.Sprintf("%s/%s", domainsBasePath, name)

req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}

root := new(DomainRoot)
resp, err := s.client.Do(req, root)
if err != nil {
return nil, resp, err
}

return root, resp, err
}

// Create a new domain
func (s *DomainsServiceOp) Create(createRequest *DomainCreateRequest) (*DomainRoot, *Response, error) {
path := domainsBasePath

req, err := s.client.NewRequest("POST", path, createRequest)
if err != nil {
return nil, nil, err
}

root := new(DomainRoot)
resp, err := s.client.Do(req, root)
if err != nil {
return nil, resp, err
}

return root, resp, err
}

// Delete droplet
func (s *DomainsServiceOp) Delete(name string) (*Response, error) {
path := fmt.Sprintf("%s/%s", domainsBasePath, name)

req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}

resp, err := s.client.Do(req, nil)

return resp, err
}

// Converts a DomainRecord to a string.
func (d DomainRecord) String() string {
return Stringify(d)
}

// Converts a DomainRecordEditRequest to a string.
func (d DomainRecordEditRequest) String() string {
return Stringify(d)
}

// Records returns a slice of DomainRecords for a domain
func (s *DomainsServiceOp) Records(domain string, opt *DomainRecordsOptions) ([]DomainRecord, *Response, error) {
func (s *DomainsServiceOp) Records(domain string, opt *ListOptions) ([]DomainRecord, *Response, error) {
path := fmt.Sprintf("%s/%s/records", domainsBasePath, domain)
path, err := addOptions(path, opt)
if err != nil {
Expand All @@ -80,13 +183,16 @@ func (s *DomainsServiceOp) Records(domain string, opt *DomainRecordsOptions) ([]
return nil, nil, err
}

records := new(DomainRecordsRoot)
resp, err := s.client.Do(req, records)
root := new(DomainRecordsRoot)
resp, err := s.client.Do(req, root)
if err != nil {
return nil, resp, err
}
if l := root.Links; l != nil {
resp.Links = l
}

return records.DomainRecords, resp, err
return root.DomainRecords, resp, err
}

// Record returns the record id from a domain
Expand Down
Loading

0 comments on commit db6b5a6

Please sign in to comment.