diff --git a/docs/use-cases/data-residency-set-hostname.md b/docs/use-cases/data-residency-set-hostname.md new file mode 100644 index 000000000..0fc0927d5 --- /dev/null +++ b/docs/use-cases/data-residency-set-hostname.md @@ -0,0 +1,37 @@ +# Choosing a data-residency to send messages to + +Use the `setDataResidency` setter to specify which host to send to: + +Send to EU (data-residency: `https://api.eu.sendgrid.com/`) +```js +const sgMail = require('@sendgrid/mail'); +sgMail.setDataResidency('eu'); +const msg = { + to: 'recipient@example.org', + from: 'sender@example.org', + subject: 'Hello world', + text: 'Hello plain world!', + html: '

Hello HTML world!

', +}; +sgMail.send(msg); +``` +Send to Global region, this is also the default host, if the setter is not used +(data-residency: `https://api.sendgrid.com/`) +```js +const sgMail = require('@sendgrid/mail'); +sgMail.setDataResidency('global'); +const msg = { + to: 'recipient@example.org', + from: 'sender@example.org', + subject: 'Hello world', + text: 'Hello plain world!', + html: '

Hello HTML world!

', +}; +sgMail.send(msg); +``` + +## Limitations + +1. Emails can only be sent to two hosts for now; 'eu' (https://api.eu.sendgrid.com/) and 'global' (https://api.eu.sendgrid.com/) +2. The default data-residency is https://api.sendgrid.com/ +3. The valid values for `region` in `client.setDataResidency(region)` are only `eu` and `global`. Case-sensitive. diff --git a/packages/client/src/classes/client.js b/packages/client/src/classes/client.js index c91768d4d..22357c0ba 100644 --- a/packages/client/src/classes/client.js +++ b/packages/client/src/classes/client.js @@ -14,11 +14,17 @@ const { const API_KEY_PREFIX = 'SG.'; const SENDGRID_BASE_URL = 'https://api.sendgrid.com/'; const TWILIO_BASE_URL = 'https://email.twilio.com/'; - +const SENDGRID_REGION = 'global'; +// Initialize the allowed regions and their corresponding hosts +const REGION_HOST_MAP = { + eu: 'https://api.eu.sendgrid.com/', + global: 'https://api.sendgrid.com/', +}; class Client { constructor() { this.auth = ''; this.impersonateSubuser = ''; + this.sendgrid_region = SENDGRID_REGION; this.defaultHeaders = { Accept: 'application/json', @@ -38,7 +44,7 @@ class Client { setApiKey(apiKey) { this.auth = 'Bearer ' + apiKey; - this.setDefaultRequest('baseUrl', SENDGRID_BASE_URL); + this.setDefaultRequest('baseUrl', REGION_HOST_MAP[this.sendgrid_region]); if (!this.isValidApiKey(apiKey)) { console.warn(`API key does not start with "${API_KEY_PREFIX}".`); @@ -94,6 +100,21 @@ class Client { return this; } + /** + * Global is the default residency (or region) + * Global region means the message will be sent through https://api.sendgrid.com + * EU region means the message will be sent through https://api.eu.sendgrid.com + **/ + setDataResidency(region) { + if (!REGION_HOST_MAP.hasOwnProperty(region)) { + console.warn('Region can only be "global" or "eu".'); + } else { + this.sendgrid_region = region; + this.setDefaultRequest('baseUrl', REGION_HOST_MAP[region]); + } + return this; + } + createHeaders(data) { // Merge data with default headers. const headers = mergeData(this.defaultHeaders, data); diff --git a/packages/client/src/client.d.ts b/packages/client/src/client.d.ts index fb84f7cb1..84075d1f9 100644 --- a/packages/client/src/client.d.ts +++ b/packages/client/src/client.d.ts @@ -30,6 +30,11 @@ declare class Client { */ setDefaultRequest(key: K | ClientRequest, value ?: ClientRequest[K]): this; + /** + * Sets the data residency as per region provided + */ + setDataResidency(region: string): this; + /** * Create headers for request */ diff --git a/packages/client/src/client.spec.js b/packages/client/src/client.spec.js index 65e0e5997..277adc287 100644 --- a/packages/client/src/client.spec.js +++ b/packages/client/src/client.spec.js @@ -1,6 +1,7 @@ 'use strict'; const nock = require('nock'); - +const sgClient = require('./client'); +let testClient = require('./client'); const testRequest = (request, statusCode) => { const sgClient = require('./client'); sgClient.setApiKey('SG.API Key'); @@ -3091,3 +3092,55 @@ describe('test_whitelabel_links__link_id__subuser_post', () => { return testRequest(request, 200); }); }); + +describe('setDataResidency', () => { + let consoleWarnSpy; + beforeEach(() => { + testClient = require('./client'); + consoleWarnSpy = sinon.spy(console, 'warn'); + }); + afterEach(() => { + console.warn.restore(); + }); + it('should have default value of hostname as https://api.sendgrid.com/', () => { + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.sendgrid.com/'); + expect(testClient.sendgrid_region).to.equal('global'); + }); + it('should send to host EU', () => { + testClient.setDataResidency('eu'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.eu.sendgrid.com/'); + }); + it('should send to host Global/default', () => { + testClient.setDataResidency('global'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.sendgrid.com/'); + expect(testClient.sendgrid_region).to.equal('global'); + }); + it('should override the existing set hostname, if data residency setter is called after', () => { + testClient.setApiKey('SG.1234567890'); + testClient.setDataResidency('eu'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.eu.sendgrid.com/'); + }); + it('should give a warning if the provided value is not allowed', () => { + testClient.setDataResidency(''); + expect(consoleWarnSpy.calledOnce).to.equal(true); + }); + it('should give a warning if the provided value is null', () => { + testClient.setDataResidency(null); + expect(consoleWarnSpy.calledOnce).to.equal(true); + }); + it('setting the API Key wont reset the region set', () => { + testClient.setDataResidency('eu'); + testClient.setApiKey('SG.1234567890'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.eu.sendgrid.com/'); + expect(testClient.sendgrid_region).to.equal('eu'); + }); + it('should send to host global and then call setApiKey', () => { + testClient.setDataResidency('global'); + testClient.setApiKey('SG.1234567890'); + expect(testClient.defaultRequest.baseUrl).to.equal('https://api.sendgrid.com/'); + expect(testClient.sendgrid_region).to.equal('global'); + + + }); +}); +