diff --git a/base_interface.go b/base_interface.go index ae826811..2f4e38c7 100644 --- a/base_interface.go +++ b/base_interface.go @@ -6,6 +6,7 @@ import ( "context" "errors" "net/http" + "net/url" "strconv" "time" @@ -20,6 +21,11 @@ const ( rateLimitSleep = 1100 ) +var allowedRegionsHostMap = map[string]string{ + "eu": "https://api.eu.sendgrid.com", + "global": "https://api.sendgrid.com", +} + type options struct { Auth string Endpoint string @@ -55,6 +61,50 @@ func requestNew(options options) rest.Request { } } +// extractEndpoint extracts the endpoint from a baseURL +func extractEndpoint(link string) (string, error) { + parsedURL, err := url.Parse(link) + if err != nil { + return "", err + } + + return parsedURL.Path, nil +} + +// SetHost changes the baseURL of the request with the host passed +/* + * This allows support for global and eu regions only. This set will likely expand in the future. + * Global should be the default + * Global region means the message should be sent through: + * HTTP: api.sendgrid.com + * EU region means the message should be sent through: + * HTTP: api.eu.sendgrid.com + */ +// @return [Request] the modified request object +func SetHost(request rest.Request, host string) (rest.Request, error) { + endpoint, err := extractEndpoint(request.BaseURL) + if err != nil { + return request, err + } + + request.BaseURL = host + endpoint + return request, nil +} + +// SetDataResidency modifies the host as per the region +// @return [Request] the modified request object +func SetDataResidency(request rest.Request, region string) (rest.Request, error) { + regionalHost, present := allowedRegionsHostMap[region] + if !present { + return request, errors.New("error: region can only be \"eu\" or \"global\"") + } + request, err := SetHost(request, regionalHost) + if err != nil { + return request, err + } + return request, nil +} + // Send sends an email through Twilio SendGrid func (cl *Client) Send(email *mail.SGMailV3) (*rest.Response, error) { return cl.SendWithContext(context.Background(), email) diff --git a/examples/dataresidency/setRegion.go b/examples/dataresidency/setRegion.go new file mode 100644 index 00000000..8376c67b --- /dev/null +++ b/examples/dataresidency/setRegion.go @@ -0,0 +1,100 @@ +package main + +import ( + "fmt" + "log" + "os" + + "github.com/sendgrid/rest" + "github.com/sendgrid/sendgrid-go/helpers/mail" + + "github.com/sendgrid/sendgrid-go" +) + +var SAMPLE_EMAIL = "test@example.com" + +// SetDataResidency : Set region for sendgrid. +func SetDataResidencyGlobal() { + message := buildHelloEmail() + request, err := buildSendgridObj("global") + if err != nil { + log.Println(err) + } else { + request.Body = mail.GetRequestBody(message) + response, err := sendgrid.API(request) + if err != nil { + log.Println(err) + } else { + fmt.Println(response.StatusCode) + fmt.Println(response.Body) + fmt.Println(response.Headers) + } + } +} + +func SetDataResidencyEu() { + message := buildHelloEmail() + request, err := buildSendgridObj("eu") + if err != nil { + log.Println(err) + } else { + request.Body = mail.GetRequestBody(message) + response, err := sendgrid.API(request) + if err != nil { + log.Println(err) + } else { + fmt.Println(response.StatusCode) + fmt.Println(response.Body) + fmt.Println(response.Headers) + } + } +} + +func SetDataResidencyDefault() { + message := buildHelloEmail() + request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "") + request.Method = "POST" + request.Body = mail.GetRequestBody(message) + response, err := sendgrid.API(request) + if err != nil { + log.Println(err) + } else { + fmt.Println(response.StatusCode) + fmt.Println(response.Body) + fmt.Println(response.Headers) + } +} + +func buildHelloEmail() *mail.SGMailV3 { + // Note that when you use this constructor an initial personalization object + // is created for you. It can be accessed via + // mail.personalization.get(0) as it is a List object + + from := mail.NewEmail("test_user", SAMPLE_EMAIL) + subject := "Sending with Twilio SendGrid is Fun" + to := mail.NewEmail("test_user", SAMPLE_EMAIL) + plainTextContent := "and easy to do anywhere, even with Go" + htmlContent := "and easy to do anywhere, even with Go" + message := mail.NewSingleEmail(from, subject, to, plainTextContent, htmlContent) + email := mail.NewEmail("test_user", SAMPLE_EMAIL) + + p := mail.NewPersonalization() + p.AddTos(email) + message.AddPersonalizations(p) + + return message +} + +func buildSendgridObj(region string) (rest.Request, error) { + request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "") + request.Method = "POST" + request, err := sendgrid.SetDataResidency(request, region) + if err != nil { + return request, err + } + return request, nil +} + +func main() { + // add your function calls here +} diff --git a/sendgrid_test.go b/sendgrid_test.go index ada4dfe1..365d46e5 100644 --- a/sendgrid_test.go +++ b/sendgrid_test.go @@ -81,6 +81,53 @@ func TestGetRequestSubuser(t *testing.T) { ShouldHaveHeaders(&request, t) } +func TestSetDataResidencyEU(t *testing.T) { + request := GetRequest("API_KEY", "", "") + request, err := SetDataResidency(request, "eu") + assert.Nil(t, err) + assert.Equal(t, "https://api.eu.sendgrid.com", request.BaseURL, "Host not correct as per the region") +} + +func TestSetDataResidencyGlobal(t *testing.T) { + request := GetRequest("API_KEY", "", "https://api.sendgrid.com") + request, err := SetDataResidency(request, "global") + assert.Nil(t, err) + assert.Equal(t, "https://api.sendgrid.com", request.BaseURL, "Host not correct as per the region") +} + +func TestSetDataResidencyOverrideHost(t *testing.T) { + request := GetRequest("API_KEY", "", "https://test.api.com") + request, err := SetDataResidency(request, "eu") + assert.Nil(t, err) + assert.Equal(t, "https://api.eu.sendgrid.com", request.BaseURL, "Host not correct as per the region") +} + +func TestSetDataResidencyOverrideDataResidency(t *testing.T) { + request := GetRequest("API_KEY", "", "") + request, err := SetDataResidency(request, "eu") + assert.Nil(t, err) + request, err = SetHost(request, "https://test.api.com") + assert.Nil(t, err) + assert.Equal(t, "https://test.api.com", request.BaseURL, "Host not correct as per the region") +} + +func TestSetDataResidencyIncorrectRegion(t *testing.T) { + request := GetRequest("API_KEY", "", "") + _, err := SetDataResidency(request, "foo") + assert.NotNil(t, err, "error: region can only be \"eu\" or \"global\"") +} + +func TestSetDataResidencyNullRegion(t *testing.T) { + request := GetRequest("API_KEY", "", "") + _, err := SetDataResidency(request, "") + assert.NotNil(t, err, "error: region can only be \"eu\" or \"global\"") +} + +func TestSetDataResidencyDefaultRegion(t *testing.T) { + request := GetRequest("API_KEY", "", "") + assert.Equal(t, "https://api.sendgrid.com", request.BaseURL, "Host not correct as per the region") +} + func getRequest(endpoint string) rest.Request { return GetRequest("SENDGRID_APIKEY", endpoint, "") }