forked from go-acme/lego
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
137 lines (111 loc) · 3.34 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package internal
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"path"
"time"
)
const defaultBaseURL = "https://api.simply.com/1/"
// Client is a Simply.com API client.
type Client struct {
HTTPClient *http.Client
baseURL *url.URL
accountName string
apiKey string
}
// NewClient creates a new Client.
func NewClient(accountName string, apiKey string) (*Client, error) {
if accountName == "" {
return nil, errors.New("credentials missing: accountName")
}
if apiKey == "" {
return nil, errors.New("credentials missing: apiKey")
}
baseURL, err := url.Parse(defaultBaseURL)
if err != nil {
return nil, err
}
return &Client{
HTTPClient: &http.Client{Timeout: 5 * time.Second},
baseURL: baseURL,
accountName: accountName,
apiKey: apiKey,
}, nil
}
// GetRecords lists all the records in the zone.
func (c *Client) GetRecords(zoneName string) ([]Record, error) {
resp, err := c.do(zoneName, "/", http.MethodGet, nil)
if err != nil {
return nil, err
}
var records []Record
err = json.Unmarshal(resp.Records, &records)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response result: %w", err)
}
return records, nil
}
// AddRecord adds a record.
func (c *Client) AddRecord(zoneName string, record Record) (int64, error) {
reqBody, err := json.Marshal(record)
if err != nil {
return 0, fmt.Errorf("failed to marshall request body: %w", err)
}
resp, err := c.do(zoneName, "/", http.MethodPost, reqBody)
if err != nil {
return 0, err
}
var rcd recordHeader
err = json.Unmarshal(resp.Record, &rcd)
if err != nil {
return 0, fmt.Errorf("failed to unmarshal response result: %w", err)
}
return rcd.ID, nil
}
// EditRecord updates a record.
func (c *Client) EditRecord(zoneName string, id int64, record Record) error {
reqBody, err := json.Marshal(record)
if err != nil {
return fmt.Errorf("failed to marshall request body: %w", err)
}
_, err = c.do(zoneName, fmt.Sprintf("%d", id), http.MethodPut, reqBody)
return err
}
// DeleteRecord deletes a record.
func (c *Client) DeleteRecord(zoneName string, id int64) error {
_, err := c.do(zoneName, fmt.Sprintf("%d", id), http.MethodDelete, nil)
return err
}
func (c *Client) do(zoneName string, endpoint string, reqMethod string, reqBody []byte) (*apiResponse, error) {
reqURL, err := c.baseURL.Parse(path.Join(c.baseURL.Path, c.accountName, c.apiKey, "my", "products", zoneName, "dns", "records", endpoint))
if err != nil {
return nil, fmt.Errorf("failed to parse endpoint: %w", err)
}
req, err := http.NewRequest(reqMethod, reqURL.String(), bytes.NewReader(reqBody))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to perform request: %w", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode >= http.StatusInternalServerError {
return nil, fmt.Errorf("unexpected error: %d", resp.StatusCode)
}
response := apiResponse{}
err = json.NewDecoder(resp.Body).Decode(&response)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
if response.Status != http.StatusOK {
return nil, fmt.Errorf("unexpected error: %s", response.Message)
}
return &response, nil
}