From b357415e728f7b386726734a099793eb84e9e812 Mon Sep 17 00:00:00 2001 From: Simone Carletti Date: Sat, 2 May 2020 17:25:42 +0200 Subject: [PATCH] Handle case where ZoneRecord name can be non present Closes GH-33 --- dnsimple/dnsimple.go | 8 ++++++++ dnsimple/live_test.go | 3 ++- dnsimple/zones_records.go | 21 ++++++++++++++++++--- dnsimple/zones_records_test.go | 28 +++++++++++++++++----------- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/dnsimple/dnsimple.go b/dnsimple/dnsimple.go index e09818f..7d4950a 100644 --- a/dnsimple/dnsimple.go +++ b/dnsimple/dnsimple.go @@ -370,3 +370,11 @@ func addURLQueryOptions(path string, options interface{}) (string, error) { return u.String(), nil } + +// Int64P is a helper routine that allocates a new int64 value +// to store v and returns a pointer to it. +func Int64P(v int64) *int64 { return &v } + +// StringP is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func StringP(v string) *string { return &v } diff --git a/dnsimple/live_test.go b/dnsimple/live_test.go index 6eaad0e..de21112 100644 --- a/dnsimple/live_test.go +++ b/dnsimple/live_test.go @@ -158,7 +158,8 @@ func TestLive_Zones(t *testing.T) { } zoneName := domainResponse.Data.Name - recordResponse, err := dnsimpleClient.Zones.CreateRecord(context.Background(), accountID, zoneName, ZoneRecord{Name: fmt.Sprintf("%v", time.Now().Unix()), Type: "TXT", Content: "Test"}) + recordName := fmt.Sprintf("%v", time.Now().Unix()) + recordResponse, err := dnsimpleClient.Zones.CreateRecord(context.Background(), accountID, zoneName, ZoneRecordAttributes{Name: &recordName, Type: "TXT", Content: "Test"}) if err != nil { t.Fatalf("Live Zones/CreateRecord() returned error: %v", err) } diff --git a/dnsimple/zones_records.go b/dnsimple/zones_records.go index e9d3899..fc7988b 100644 --- a/dnsimple/zones_records.go +++ b/dnsimple/zones_records.go @@ -5,7 +5,7 @@ import ( "fmt" ) -// ZoneRecord represents a DNS record in DNSimple. +// ZoneRecord represents a zone record in DNSimple. type ZoneRecord struct { ID int64 `json:"id,omitempty"` ZoneID string `json:"zone_id,omitempty"` @@ -21,6 +21,21 @@ type ZoneRecord struct { UpdatedAt string `json:"updated_at,omitempty"` } +// ZoneRecordAttributes represents the attributes you can send to create/update a zone record. +// +// Compared to most other calls in this library, you should not use ZoneRecord as payload for record calls. +// This is because it can lead to side effects due to the inability of go to distinguish between a non-present string +// and an empty string. Name can be both, therefore a specific struct is required. +type ZoneRecordAttributes struct { + ZoneID string `json:"zone_id,omitempty"` + Type string `json:"type,omitempty"` + Name *string `json:"name"` + Content string `json:"content,omitempty"` + TTL int `json:"ttl,omitempty"` + Priority int `json:"priority,omitempty"` + Regions []string `json:"regions,omitempty"` +} + func zoneRecordPath(accountID string, zoneName string, recordID int64) (path string) { path = fmt.Sprintf("/%v/zones/%v/records", accountID, zoneName) if recordID != 0 { @@ -81,7 +96,7 @@ func (s *ZonesService) ListRecords(ctx context.Context, accountID string, zoneNa // CreateRecord creates a zone record. // // See https://developer.dnsimple.com/v2/zones/records/#createZoneRecord -func (s *ZonesService) CreateRecord(ctx context.Context, accountID string, zoneName string, recordAttributes ZoneRecord) (*ZoneRecordResponse, error) { +func (s *ZonesService) CreateRecord(ctx context.Context, accountID string, zoneName string, recordAttributes ZoneRecordAttributes) (*ZoneRecordResponse, error) { path := versioned(zoneRecordPath(accountID, zoneName, 0)) recordResponse := &ZoneRecordResponse{} @@ -113,7 +128,7 @@ func (s *ZonesService) GetRecord(ctx context.Context, accountID string, zoneName // UpdateRecord updates a zone record. // // See https://developer.dnsimple.com/v2/zones/records/#updateZoneRecord -func (s *ZonesService) UpdateRecord(ctx context.Context, accountID string, zoneName string, recordID int64, recordAttributes ZoneRecord) (*ZoneRecordResponse, error) { +func (s *ZonesService) UpdateRecord(ctx context.Context, accountID string, zoneName string, recordID int64, recordAttributes ZoneRecordAttributes) (*ZoneRecordResponse, error) { path := versioned(zoneRecordPath(accountID, zoneName, recordID)) recordResponse := &ZoneRecordResponse{} resp, err := s.client.patch(ctx, path, recordAttributes, recordResponse) diff --git a/dnsimple/zones_records_test.go b/dnsimple/zones_records_test.go index 6e249ea..0377eb5 100644 --- a/dnsimple/zones_records_test.go +++ b/dnsimple/zones_records_test.go @@ -102,7 +102,7 @@ func TestZonesService_CreateRecord(t *testing.T) { }) accountID := "1010" - recordValues := ZoneRecord{Name: "foo", Content: "mxa.example.com", Type: "MX"} + recordValues := ZoneRecordAttributes{Name: StringP("foo"), Content: "mxa.example.com", Type: "MX"} recordResponse, err := client.Zones.CreateRecord(context.Background(), accountID, "example.com", recordValues) if err != nil { @@ -141,7 +141,7 @@ func TestZonesService_CreateRecord_BlankName(t *testing.T) { io.Copy(w, httpResponse.Body) }) - recordValues := ZoneRecord{Name: "", Content: "127.0.0.1", Type: "A"} + recordValues := ZoneRecordAttributes{Name: StringP(""), Content: "127.0.0.1", Type: "A"} recordResponse, err := client.Zones.CreateRecord(context.Background(), "1010", "example.com", recordValues) if err != nil { @@ -161,7 +161,7 @@ func TestZonesService_CreateRecord_Regions(t *testing.T) { setupMockServer() defer teardownMockServer() - var recordValues ZoneRecord + var recordValues ZoneRecordAttributes mux.HandleFunc("/v2/1/zones/example.com/records", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/createZoneRecord/created.http") @@ -173,7 +173,8 @@ func TestZonesService_CreateRecord_Regions(t *testing.T) { io.Copy(w, httpResponse.Body) }) - recordValues = ZoneRecord{Name: "foo", Regions: []string{}} + recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{}} + if _, err := client.Zones.CreateRecord(context.Background(), "1", "example.com", recordValues); err != nil { t.Fatalf("Zones.CreateRecord() returned error: %v", err) } @@ -188,7 +189,8 @@ func TestZonesService_CreateRecord_Regions(t *testing.T) { io.Copy(w, httpResponse.Body) }) - recordValues = ZoneRecord{Name: "foo", Regions: []string{"global"}} + recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{"global"}} + if _, err := client.Zones.CreateRecord(context.Background(), "2", "example.com", recordValues); err != nil { t.Fatalf("Zones.CreateRecord() returned error: %v", err) } @@ -203,7 +205,8 @@ func TestZonesService_CreateRecord_Regions(t *testing.T) { io.Copy(w, httpResponse.Body) }) - recordValues = ZoneRecord{Name: "foo", Regions: []string{"global"}} + recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{"global"}} + if _, err := client.Zones.CreateRecord(context.Background(), "2", "example.com", recordValues); err != nil { t.Fatalf("Zones.CreateRecord() returned error: %v", err) } @@ -268,7 +271,7 @@ func TestZonesService_UpdateRecord(t *testing.T) { }) accountID := "1010" - recordValues := ZoneRecord{Name: "foo", Content: "127.0.0.1"} + recordValues := ZoneRecordAttributes{Name: StringP("foo"), Content: "127.0.0.1"} recordResponse, err := client.Zones.UpdateRecord(context.Background(), accountID, "example.com", 5, recordValues) if err != nil { @@ -288,7 +291,7 @@ func TestZonesService_UpdateRecord_Regions(t *testing.T) { setupMockServer() defer teardownMockServer() - var recordValues ZoneRecord + var recordValues ZoneRecordAttributes mux.HandleFunc("/v2/1/zones/example.com/records/1", func(w http.ResponseWriter, r *http.Request) { httpResponse := httpResponseFixture(t, "/api/updateZoneRecord/success.http") @@ -300,7 +303,8 @@ func TestZonesService_UpdateRecord_Regions(t *testing.T) { io.Copy(w, httpResponse.Body) }) - recordValues = ZoneRecord{Name: "foo", Regions: []string{}} + recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{}} + if _, err := client.Zones.UpdateRecord(context.Background(), "1", "example.com", 1, recordValues); err != nil { t.Fatalf("Zones.UpdateRecord() returned error: %v", err) } @@ -315,7 +319,8 @@ func TestZonesService_UpdateRecord_Regions(t *testing.T) { io.Copy(w, httpResponse.Body) }) - recordValues = ZoneRecord{Name: "foo", Regions: []string{"global"}} + recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{"global"}} + if _, err := client.Zones.UpdateRecord(context.Background(), "2", "example.com", 1, recordValues); err != nil { t.Fatalf("Zones.UpdateRecord() returned error: %v", err) } @@ -330,7 +335,8 @@ func TestZonesService_UpdateRecord_Regions(t *testing.T) { io.Copy(w, httpResponse.Body) }) - recordValues = ZoneRecord{Name: "foo", Regions: []string{"global"}} + recordValues = ZoneRecordAttributes{Name: StringP("foo"), Regions: []string{"global"}} + if _, err := client.Zones.UpdateRecord(context.Background(), "2", "example.com", 1, recordValues); err != nil { t.Fatalf("Zones.UpdateRecord() returned error: %v", err) }