Repository: cloudflare/cloudflare-go (go)

Issue:
Provide ZoneSetType method and add Type to ZoneOpts
### Current cloudflare-go version

master

### Description

The CloudFlare API proides a way to make a zone "CNAME-only" (i.e. Customer manages the DNS for the zone and just points a CNAME at CloudFlare). This is known as a "partial" type zone in the API. The Go SDK should also provide a way to toggle this (it already allows the type to be set on zone creation but not to modify the type on an existing zone).

### Use cases

I would like to be able to manage a CNAME-only zone using the Terraform provider.

### Potential cloudflare-go usage

```go
client := meta.(*cloudflare.API)
newType = "partial"
client.ZoneSetPaused(context.Background(), zoneID, newType)
```


### References

_No response_

Pull request description:
zone: Add ZoneSetType (resolves #727)
The ZoneSetType method adds the ability to toggle the "CNAME-only" zone type setting via the SDK. Currently this can only be set during zone creation.

## Description

A new method was added (`ZoneSetType` following the pattern of `ZoneSetPaused`). API Documentation around this functionality is a little sketchy because this particular property update is not documented separately from the zone creation functionality, however it does seem to work as expected when called via cURL:

```bash
curl -s -X PATCH \
  -H "Content-Type: application/json" \
  -H "X-Auth-Key: ${CLOUDFLARE_API_KEY}" \
  -H "X-Auth-Email: ${CLOUDFLARE_EMAIL}" \
  "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}"
```

returns:

```json
{
  "result": {
    ...
    "type": "partial",
    "verification_key": "VERIFICATION-KEY",
    "cname_suffix": "cdn.cloudflare.net",
    ...
  }
}
```

## Has your change been tested?

Newly created unit test passes:
```bash
❯ go test -race -v -timeout 30s -run ^TestZoneSetType$ github.com/cloudflare/cloudflare-go
=== RUN   TestZoneSetType
--- PASS: TestZoneSetType (0.00s)
PASS
ok  	github.com/cloudflare/cloudflare-go	0.172s
```

All other unit tests pass as well.

Additionally, the modified library was wired up to Terraform and successfully used to convert a zone from "full" to "partial."

## Types of changes

What sort of change does your code introduce/modify?

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist:

- [x] My code follows the code style of this project.
- [x] My change requires a change to the documentation.
- [x] I have updated the documentation accordingly.
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.
- [x] This change is using publicly documented (api.cloudflare.com or developers.cloudflare.com) and stable APIs.

[1]: https://help.github.com/articles/closing-issues-using-keywords/


Patch:
diff --git a/zone.go b/zone.go
index eafaab0f1..083e75ee7 100644
--- a/zone.go
+++ b/zone.go
@@ -523,6 +523,7 @@ type ZoneOptions struct {
 	Paused   *bool     `json:"paused,omitempty"`
 	VanityNS []string  `json:"vanity_name_servers,omitempty"`
 	Plan     *ZonePlan `json:"plan,omitempty"`
+	Type     string    `json:"type,omitempty"`
 }
 
 // ZoneSetPaused pauses Cloudflare service for the entire zone, sending all
@@ -537,6 +538,21 @@ func (api *API) ZoneSetPaused(ctx context.Context, zoneID string, paused bool) (
 	return zone, nil
 }
 
+// ZoneSetType toggles the type for an existing zone.
+//
+// Valid values for `type` are "full" and "partial"
+//
+// API reference: https://api.cloudflare.com/#zone-edit-zone
+func (api *API) ZoneSetType(ctx context.Context, zoneID string, zoneType string) (Zone, error) {
+	zoneopts := ZoneOptions{Type: zoneType}
+	zone, err := api.EditZone(ctx, zoneID, zoneopts)
+	if err != nil {
+		return Zone{}, err
+	}
+
+	return zone, nil
+}
+
 // ZoneSetVanityNS sets custom nameservers for the zone.
 // These names must be within the same zone.
 func (api *API) ZoneSetVanityNS(ctx context.Context, zoneID string, ns []string) (Zone, error) {
@@ -591,7 +607,7 @@ func (api *API) ZoneUpdatePlan(ctx context.Context, zoneID string, planType stri
 
 // EditZone edits the given zone.
 //
-// This is usually called by ZoneSetPaused or ZoneSetVanityNS.
+// This is usually called by ZoneSetPaused, ZoneSetType, or ZoneSetVanityNS.
 //
 // API reference: https://api.cloudflare.com/#zone-edit-zone-properties
 func (api *API) EditZone(ctx context.Context, zoneID string, zoneOpts ZoneOptions) (Zone, error) {


Test patch:
diff --git a/zone_test.go b/zone_test.go
index 7e21e05ff..fc820cd87 100644
--- a/zone_test.go
+++ b/zone_test.go
@@ -1338,6 +1338,34 @@ func TestUpdateZoneDNSSEC(t *testing.T) {
 	}
 }
 
+func TestZoneSetType(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method)
+
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprintf(w, `{
+			"result": {
+				"type": "partial",
+				"verification_key": "000000000-000000000",
+				"modified_on": "2014-01-01T05:20:00Z"
+				}
+		}`)
+	}
+
+	mux.HandleFunc("/zones/foo", handler)
+
+	z, err := client.ZoneSetType(context.Background(), "foo", "partial")
+	if assert.NoError(t, err) {
+		assert.Equal(t, z.Type, "partial")
+		assert.Equal(t, z.VerificationKey, "000000000-000000000")
+		time, _ := time.Parse("2006-01-02T15:04:05Z", "2014-01-01T05:20:00Z")
+		assert.Equal(t, z.ModifiedOn, time)
+	}
+}
+
 func parsePage(t *testing.T, total int, s string) (int, bool) {
 	if s == "" {
 		return 1, true