diff --git a/contentful.go b/contentful.go index 9a82974..5179e15 100644 --- a/contentful.go +++ b/contentful.go @@ -132,6 +132,20 @@ func NewCPA(token string) *Contentful { return c } +// SetRegion configures all API base URLs for the given region. +// RegionUS and the empty string are no-ops; the client keeps its constructor defaults. +func (c *Contentful) SetRegion(region Region) *Contentful { + if region == "" || region == RegionUS { + return c + } + subdomain := "." + string(region) + c.BaseURL = strings.Replace(c.BaseURL, ".contentful.com", subdomain+".contentful.com", 1) + if c.UploadURL != "" { + c.UploadURL = strings.Replace(c.UploadURL, ".contentful.com", subdomain+".contentful.com", 1) + } + return c +} + // SetOrganization sets the given organization id func (c *Contentful) SetOrganization(organizationID string) *Contentful { c.Headers["X-Contentful-Organization"] = organizationID diff --git a/contentful_test.go b/contentful_test.go index ed44b57..7e0ded4 100644 --- a/contentful_test.go +++ b/contentful_test.go @@ -166,6 +166,35 @@ func TestContentfulSetOrganization(t *testing.T) { assert.Equal(t, organizationID, cma.Headers["X-Contentful-Organization"]) } +func TestSetRegion(t *testing.T) { + t.Run("US is a no-op on CMA", func(t *testing.T) { + c := NewCMA(CMAToken) + c.SetRegion(RegionUS) + assert.Equal(t, "https://api.contentful.com", c.BaseURL) + assert.Equal(t, "https://upload.contentful.com", c.UploadURL) + }) + t.Run("EU sets CMA BaseURL and UploadURL", func(t *testing.T) { + c := NewCMA(CMAToken) + c.SetRegion(RegionEU) + assert.Equal(t, "https://api.eu.contentful.com", c.BaseURL) + assert.Equal(t, "https://upload.eu.contentful.com", c.UploadURL) + }) + t.Run("EU sets CDA BaseURL", func(t *testing.T) { + c := NewCDA(CDAToken) + c.SetRegion(RegionEU) + assert.Equal(t, "https://cdn.eu.contentful.com", c.BaseURL) + }) + t.Run("EU sets CPA BaseURL", func(t *testing.T) { + c := NewCPA(CPAToken) + c.SetRegion(RegionEU) + assert.Equal(t, "https://preview.eu.contentful.com", c.BaseURL) + }) + t.Run("SetRegion is chainable", func(t *testing.T) { + c := NewCMA(CMAToken).SetRegion(RegionEU) + assert.Equal(t, "https://api.eu.contentful.com", c.BaseURL) + }) +} + func TestContentfulSetClient(t *testing.T) { newClient := &http.Client{} cma := NewCMA(CMAToken) diff --git a/region.go b/region.go new file mode 100644 index 0000000..fdc9942 --- /dev/null +++ b/region.go @@ -0,0 +1,23 @@ +package contentful + +import "fmt" + +// Region identifies a Contentful infrastructure region. +type Region string + +const ( + RegionUS Region = "us" + RegionEU Region = "eu" +) + +// ParseRegion validates s against the known regions and returns the typed Region. +// An empty string is accepted and represents the default (US) region. +func ParseRegion(s string) (Region, error) { + r := Region(s) + switch r { + case "", RegionUS, RegionEU: + return r, nil + default: + return "", fmt.Errorf("unknown region %q: supported values are %q and %q", s, RegionUS, RegionEU) + } +} diff --git a/region_test.go b/region_test.go new file mode 100644 index 0000000..5331bbb --- /dev/null +++ b/region_test.go @@ -0,0 +1,34 @@ +package contentful + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestParseRegion(t *testing.T) { + t.Run("empty string is valid", func(t *testing.T) { + r, err := ParseRegion("") + require.NoError(t, err) + assert.Equal(t, Region(""), r) + }) + t.Run("us is valid", func(t *testing.T) { + r, err := ParseRegion("us") + require.NoError(t, err) + assert.Equal(t, RegionUS, r) + }) + t.Run("eu is valid", func(t *testing.T) { + r, err := ParseRegion("eu") + require.NoError(t, err) + assert.Equal(t, RegionEU, r) + }) + t.Run("uppercase EU is rejected", func(t *testing.T) { + _, err := ParseRegion("EU") + require.Error(t, err) + }) + t.Run("unknown region is rejected", func(t *testing.T) { + _, err := ParseRegion("ap") + require.Error(t, err) + }) +}