2020-05-08 10:26:44 +00:00
|
|
|
package internal
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2021-08-25 09:44:11 +00:00
|
|
|
"io"
|
2020-05-08 10:26:44 +00:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
)
|
|
|
|
|
|
|
|
const defaultBaseURL = "https://api.netlify.com/api/v1"
|
|
|
|
|
|
|
|
// Client Netlify API client.
|
|
|
|
type Client struct {
|
|
|
|
HTTPClient *http.Client
|
|
|
|
BaseURL string
|
|
|
|
|
|
|
|
token string
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewClient creates a new Client.
|
|
|
|
func NewClient(token string) *Client {
|
|
|
|
return &Client{
|
|
|
|
HTTPClient: http.DefaultClient,
|
|
|
|
BaseURL: defaultBaseURL,
|
|
|
|
token: token,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRecords gets a DNS records.
|
|
|
|
func (c *Client) GetRecords(zoneID string) ([]DNSRecord, error) {
|
|
|
|
endpoint, err := c.createEndpoint("dns_zones", zoneID, "dns_records")
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to parse endpoint: %w", err)
|
|
|
|
}
|
|
|
|
|
2023-02-09 16:19:58 +00:00
|
|
|
req, err := http.NewRequest(http.MethodGet, endpoint.String(), nil)
|
2020-05-08 10:26:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token))
|
|
|
|
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("API call failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
|
2021-08-25 09:44:11 +00:00
|
|
|
body, err := io.ReadAll(resp.Body)
|
2020-05-08 10:26:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read response body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return nil, fmt.Errorf("invalid status code: %s: %s", resp.Status, string(body))
|
|
|
|
}
|
|
|
|
|
|
|
|
var records []DNSRecord
|
|
|
|
err = json.Unmarshal(body, &records)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to marshal response body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return records, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateRecord creates a DNS records.
|
|
|
|
func (c *Client) CreateRecord(zoneID string, record DNSRecord) (*DNSRecord, error) {
|
|
|
|
endpoint, err := c.createEndpoint("dns_zones", zoneID, "dns_records")
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to parse endpoint: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
marshaledRecord, err := json.Marshal(record)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to marshal request body: %w", err)
|
|
|
|
}
|
|
|
|
|
2023-02-09 16:19:58 +00:00
|
|
|
req, err := http.NewRequest(http.MethodPost, endpoint.String(), bytes.NewReader(marshaledRecord))
|
2020-05-08 10:26:44 +00:00
|
|
|
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; charset=utf-8")
|
|
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token))
|
|
|
|
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("API call failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
|
2021-08-25 09:44:11 +00:00
|
|
|
body, err := io.ReadAll(resp.Body)
|
2020-05-08 10:26:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read response body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusCreated {
|
|
|
|
return nil, fmt.Errorf("invalid status code: %s: %s", resp.Status, string(body))
|
|
|
|
}
|
|
|
|
|
|
|
|
var recordResp DNSRecord
|
|
|
|
err = json.Unmarshal(body, &recordResp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to marshal response body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &recordResp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveRecord removes a DNS records.
|
2020-07-09 23:48:18 +00:00
|
|
|
func (c *Client) RemoveRecord(zoneID, recordID string) error {
|
2020-05-08 10:26:44 +00:00
|
|
|
endpoint, err := c.createEndpoint("dns_zones", zoneID, "dns_records", recordID)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to parse endpoint: %w", err)
|
|
|
|
}
|
|
|
|
|
2023-02-09 16:19:58 +00:00
|
|
|
req, err := http.NewRequest(http.MethodDelete, endpoint.String(), nil)
|
2020-05-08 10:26:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to create request: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token))
|
|
|
|
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("API call failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
|
2021-08-25 09:44:11 +00:00
|
|
|
body, err := io.ReadAll(resp.Body)
|
2020-05-08 10:26:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read response body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusNoContent {
|
|
|
|
return fmt.Errorf("invalid status code: %s: %s", resp.Status, string(body))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-02-09 16:19:58 +00:00
|
|
|
func (c *Client) createEndpoint(parts ...string) (*url.URL, error) {
|
2020-05-08 10:26:44 +00:00
|
|
|
base, err := url.Parse(c.BaseURL)
|
|
|
|
if err != nil {
|
2023-02-09 16:19:58 +00:00
|
|
|
return nil, fmt.Errorf("failed to parse base URL: %w", err)
|
2020-05-08 10:26:44 +00:00
|
|
|
}
|
|
|
|
|
2023-02-09 16:19:58 +00:00
|
|
|
return base.JoinPath(parts...), nil
|
2020-05-08 10:26:44 +00:00
|
|
|
}
|