Skip to content

Commit

Permalink
DEVEXP-384: Support regions for Fax API (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
asein-sinch authored Apr 8, 2024
1 parent 65a675d commit 93179be
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 50 deletions.
6 changes: 3 additions & 3 deletions examples/simple-examples/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
getRegion,
SinchClient,
Region,
SmsRegion,
ConversationService,
FaxService,
NumbersService,
Expand Down Expand Up @@ -37,8 +37,8 @@ export const initSmsServiceWithProjectId = (): SmsService => {
const initSmsClient = (): Pick<SinchClient, 'sms'> => {
const servicePlanId = process.env.SINCH_SERVICE_PLAN_ID || '';
const apiToken = process.env.SINCH_API_TOKEN || '';
const region = getRegion(process.env.SMS_REGION) || Region.UNITED_STATES;
return new SinchClient({ servicePlanId, apiToken, region });
const smsRegion = getRegion(process.env.SMS_REGION) || SmsRegion.UNITED_STATES;
return new SinchClient({ servicePlanId, apiToken, smsRegion });
};

export const initSmsServiceWithServicePlanId = (): SmsService => {
Expand Down
11 changes: 5 additions & 6 deletions packages/conversation/src/rest/v1/conversation-domain-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
ApiFetchClient,
buildOAuth2ApiClientOptions,
ConversationRegion,
Region,
SinchClientParameters,
UnifiedCredentials,
} from '@sinch/sdk-client';
Expand Down Expand Up @@ -35,10 +34,10 @@ export class ConversationDomainApi implements Api {

/**
* Update the region in the basePath
* @param {Region} region - The new region to send the requests to
* @param {ConversationRegion} region - The new region to send the requests to
*/
public setRegion(region: Region) {
this.sinchClientParameters.region = region;
public setRegion(region: ConversationRegion) {
this.sinchClientParameters.conversationRegion = region;
if (this.client) {
this.client.apiClientOptions.hostname = this.buildHostname(region);
}
Expand Down Expand Up @@ -76,7 +75,7 @@ export class ConversationDomainApi implements Api {
*/
public getSinchClient(): ApiClient {
if (!this.client) {
const region = this.sinchClientParameters.region || Region.UNITED_STATES;
const region = this.sinchClientParameters.conversationRegion || ConversationRegion.UNITED_STATES;
if(!Object.values(ConversationRegion).includes((region as unknown) as ConversationRegion)) {
console.warn(`The region '${region}' is not supported for the Conversation API`);
}
Expand All @@ -87,7 +86,7 @@ export class ConversationDomainApi implements Api {
return this.client;
}

private buildHostname(region: Region) {
private buildHostname(region: ConversationRegion) {
switch (this.apiName) {
case 'TemplatesV1Api':
case 'TemplatesV2Api':
Expand Down
33 changes: 17 additions & 16 deletions packages/conversation/tests/rest/v1/conversation-domain-api.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ConversationDomainApi } from '../../../src/rest/v1/conversation-domain-api';
import { TemplatesV2Api } from '../../../src';
import { ApiHostname, Region, UnifiedCredentials } from '@sinch/sdk-client';
import { ApiHostname, ConversationRegion, UnifiedCredentials } from '@sinch/sdk-client';

describe('Conversation API', () => {
let conversationApi: ConversationDomainApi;
Expand All @@ -25,23 +25,24 @@ describe('Conversation API', () => {
});

it('should change the URL when specifying a different region', () => {
params.region = Region.EUROPE;
params.conversationRegion = ConversationRegion.EUROPE;
conversationApi = new ConversationDomainApi(params, 'dummy');
conversationApi.getSinchClient();
expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://eu.conversation.api.sinch.com');
});

it('should log a warning when using an unsupported region', async () => {
params.region = Region.CANADA;
conversationApi = new ConversationDomainApi(params, 'dummy');
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
conversationApi.getSinchClient();
// Add a small delay to allow jest to capture the warning
setTimeout(() => {
expect(consoleWarnSpy).toHaveBeenCalledWith('The region \'ca\' is not supported for the Conversation API');
consoleWarnSpy.mockRestore();
}, 20);
});
// TODO: Temporarily disabled. Will be back with DEVEXP-381
// it('should log a warning when using an unsupported region', async () => {

Check warning on line 35 in packages/conversation/tests/rest/v1/conversation-domain-api.test.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Some tests seem to be commented

Check warning on line 35 in packages/conversation/tests/rest/v1/conversation-domain-api.test.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Some tests seem to be commented
// params.conversationRegion = 'unknown';
// conversationApi = new ConversationDomainApi(params, 'dummy');
// const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
// conversationApi.getSinchClient();
// // Add a small delay to allow jest to capture the warning
// setTimeout(() => {
// expect(consoleWarnSpy).toHaveBeenCalledWith('The region \'ca\' is not supported for the Conversation API');
// consoleWarnSpy.mockRestore();
// }, 20);
// });

it('should use the hostname parameter but not for templates', () => {
params.conversationHostname = CUSTOM_HOSTNAME;
Expand Down Expand Up @@ -83,7 +84,7 @@ describe('Conversation API', () => {

it ('should update the region', () => {
conversationApi = new ConversationDomainApi(params, 'dummy');
conversationApi.setRegion(Region.EUROPE);
conversationApi.setRegion(ConversationRegion.EUROPE);
conversationApi.getSinchClient();
expect(conversationApi.client).toBeDefined();
expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://eu.conversation.api.sinch.com');
Expand All @@ -94,7 +95,7 @@ describe('Conversation API', () => {
conversationApi.getSinchClient();
expect(conversationApi.client).toBeDefined();
expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://us.template.api.sinch.com');
conversationApi.setRegion(Region.EUROPE);
conversationApi.setRegion(ConversationRegion.EUROPE);
expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://eu.template.api.sinch.com');
});

Expand All @@ -103,7 +104,7 @@ describe('Conversation API', () => {
conversationApi.getSinchClient();
expect(conversationApi.client).toBeDefined();
expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://us.template.api.sinch.com');
conversationApi.setRegion(Region.EUROPE);
conversationApi.setRegion(ConversationRegion.EUROPE);
expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://eu.template.api.sinch.com');
});

Expand Down
4 changes: 3 additions & 1 deletion packages/fax/src/rest/v3/fax-domain-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
SinchClientParameters,
UnifiedCredentials,
buildOAuth2ApiClientOptions,
FaxRegion,
} from '@sinch/sdk-client';

export class FaxDomainApi implements Api {
Expand Down Expand Up @@ -60,7 +61,8 @@ export class FaxDomainApi implements Api {
if (!this.client) {
const apiClientOptions = buildOAuth2ApiClientOptions(this.sinchClientParameters, 'Fax');
this.client = new ApiFetchClient(apiClientOptions);
this.client.apiClientOptions.hostname = this.sinchClientParameters.faxHostname ?? 'https://fax.api.sinch.com';
const region: FaxRegion = this.sinchClientParameters.faxRegion || FaxRegion.DEFAULT;
this.client.apiClientOptions.hostname = this.sinchClientParameters.faxHostname ?? `https://${region}fax.api.sinch.com`;
}
return this.client;
}
Expand Down
9 changes: 8 additions & 1 deletion packages/fax/tests/rest/v3/fax-domain-api.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FaxDomainApi } from '../../../src/rest/v3/fax-domain-api';
import { ApiHostname, UnifiedCredentials } from '@sinch/sdk-client';
import { ApiHostname, FaxRegion, UnifiedCredentials } from '@sinch/sdk-client';

describe('Fax API', () => {
let faxApi: FaxDomainApi;
Expand All @@ -21,6 +21,13 @@ describe('Fax API', () => {
expect(faxApi.client?.apiClientOptions.hostname).toBe('https://fax.api.sinch.com');
});

it('should change the URL when specifying a different region', () => {
params.faxRegion = FaxRegion.SOUTHEAST_ASIA_1;
faxApi = new FaxDomainApi(params, 'dummy');
faxApi.getSinchClient();
expect(faxApi.client?.apiClientOptions.hostname).toBe('https://apse1.fax.api.sinch.com');
});

it('should use the hostname parameter', () => {
params.faxHostname = CUSTOM_HOSTNAME;
faxApi = new FaxDomainApi(params, 'dummy');
Expand Down
6 changes: 3 additions & 3 deletions packages/sdk-client/src/api/api-client-options-helper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Region, SinchClientParameters } from '../domain';
import { SmsRegion, SinchClientParameters } from '../domain';
import { ApiClientOptions } from './api-client-options';
import {
ApiTokenRequest,
Expand Down Expand Up @@ -37,12 +37,12 @@ export const buildApplicationSignedApiClientOptions = (
};

export const buildFlexibleOAuth2OrApiTokenApiClientOptions = (
params: SinchClientParameters, region: Region, apiName: string,
params: SinchClientParameters, region: SmsRegion, apiName: string,
): ApiClientOptions => {
let apiClientOptions: ApiClientOptions | undefined;
// Check the region: if US or EU, try to use the OAuth2 authentication with the access key / secret under the project Id
if (!params.forceServicePlanIdUsageForSmsApi
&& (region === Region.UNITED_STATES || region === Region.EUROPE)) {
&& (region === SmsRegion.UNITED_STATES || region === SmsRegion.EUROPE)) {
// Let's check the required parameters for OAuth2 authentication
if (params.projectId && params.keyId && params.keySecret) {
apiClientOptions = {
Expand Down
25 changes: 19 additions & 6 deletions packages/sdk-client/src/domain/domain-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ export interface UnifiedCredentials {
/** The client secret used for authentication. You can find this ONLY when creating a new key. */
keySecret: string;
/** The region for the SMS API. Default region is US */
region?: Region;
smsRegion?: SmsRegion;
/** The region for the Fax API. Default is auto-routing */
faxRegion?: FaxRegion;
/** The region for the Conversation API. Default region is US */
conversationRegion?: ConversationRegion;
}

export interface ServicePlanIdCredentials {
Expand All @@ -27,7 +31,7 @@ export interface ServicePlanIdCredentials {
/** boolean to force the usage of the service plan Id + API token as credentials for the SMS API*/
forceServicePlanIdUsageForSmsApi?: boolean;
/** The region for the SMS API. Default region is US */
region?: Region;
smsRegion?: SmsRegion;
}

export interface ApplicationCredentials {
Expand Down Expand Up @@ -69,22 +73,22 @@ export const isServicePlanIdCredentials = (credentials: any): credentials is Ser
&& candidate.apiToken !== undefined;
};

export enum Region {
export enum SmsRegion {
UNITED_STATES = 'us',
EUROPE = 'eu',
BRAZIL = 'br',
CANADA = 'ca',
AUSTRALIA = 'au'
}

export function getRegion(value: string | undefined): Region | undefined {
export function getRegion(value: string | undefined): SmsRegion | undefined {
if (!value) {
return undefined;
}

for (const region of Object.values(Region)) {
for (const region of Object.values(SmsRegion)) {
if (region === value.toLowerCase()) {
return region as Region;
return region as SmsRegion;
}
}
console.error(`No region exist for the value '${value}'`);
Expand All @@ -100,6 +104,15 @@ export enum VoiceRegion {
SOUTHEAST_ASIA_2 = '-apse2'
}

export enum FaxRegion {
DEFAULT = '',
UNITED_STATES = 'use1.',
EUROPE = 'eu1.',
SOUTH_AMERICA = 'sae1.',
SOUTHEAST_ASIA_1 = 'apse1.',
SOUTHEAST_ASIA_2 = 'apse2.'
}

export enum ConversationRegion {
UNITED_STATES = 'us',
EUROPE = 'eu',
Expand Down
18 changes: 9 additions & 9 deletions packages/sdk-client/tests/api/api-client-options-helper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
buildOAuth2ApiClientOptions,
Oauth2TokenRequest,
PluginRunner,
Region,
SmsRegion,
SigningRequest,
SinchClientParameters,
XTimestampRequest,
Expand Down Expand Up @@ -157,7 +157,7 @@ describe('API Client Options helper', () => {
servicePlanId: 'SERVICE_PLAN_ID',
apiToken: 'API_TOKEN',
};
const region = Region.EUROPE;
const region = SmsRegion.EUROPE;

// When
const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo');
Expand All @@ -179,7 +179,7 @@ describe('API Client Options helper', () => {
servicePlanId: 'SERVICE_PLAN_ID',
apiToken: 'API_TOKEN',
};
const region = Region.CANADA;
const region = SmsRegion.CANADA;

// When
const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo');
Expand All @@ -201,7 +201,7 @@ describe('API Client Options helper', () => {
apiToken: 'API_TOKEN',
forceServicePlanIdUsageForSmsApi: true,
};
const region = Region.EUROPE;
const region = SmsRegion.EUROPE;

// When
const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo');
Expand All @@ -221,7 +221,7 @@ describe('API Client Options helper', () => {
requestPlugins: [dummyRequestPlugin],
responsePlugins: [dummyResponsePlugin],
};
const region = Region.CANADA;
const region = SmsRegion.CANADA;

// When
const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo');
Expand All @@ -237,7 +237,7 @@ describe('API Client Options helper', () => {
const params: SinchClientParameters = {
projectId: 'PROJECT_ID',
};
const region = Region.EUROPE;
const region = SmsRegion.EUROPE;

// When
const buildApiClientOptionsFunction = () => buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo');
Expand All @@ -252,7 +252,7 @@ describe('API Client Options helper', () => {
const params: SinchClientParameters = {
servicePlanId: 'SERVICE_PLAN_ID',
};
const region = Region.EUROPE;
const region = SmsRegion.EUROPE;

// When
const buildApiClientOptionsFunction = () => buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo');
Expand All @@ -269,7 +269,7 @@ describe('API Client Options helper', () => {
keyId: 'KEY_ID',
keySecret: 'KEY_SECRET',
};
const region = Region.CANADA;
const region = SmsRegion.CANADA;

// When
const buildApiClientOptionsFunction = () => buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo');
Expand All @@ -287,7 +287,7 @@ describe('API Client Options helper', () => {
keySecret: 'KEY_SECRET',
forceServicePlanIdUsageForSmsApi: true,
};
const region = Region.EUROPE;
const region = SmsRegion.EUROPE;

// When
const buildApiClientOptionsFunction = () => buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo');
Expand Down
4 changes: 2 additions & 2 deletions packages/sms/src/rest/v1/sms-domain-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
ApiFetchClient,
buildFlexibleOAuth2OrApiTokenApiClientOptions,
SinchClientParameters,
Region,
SmsRegion,
UnifiedCredentials,
ServicePlanIdCredentials,
} from '@sinch/sdk-client';
Expand Down Expand Up @@ -65,7 +65,7 @@ export class SmsDomainApi implements Api {
*/
public getSinchClient(): ApiClient {
if (!this.client) {
const region = this.sinchClientParameters.region || Region.UNITED_STATES;
const region = this.sinchClientParameters.smsRegion || SmsRegion.UNITED_STATES;
const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(this.sinchClientParameters, region, 'SMS');
this.client = new ApiFetchClient(apiClientOptions);
this.client.apiClientOptions.hostname = this.sinchClientParameters.smsHostname ?? `https://${apiClientOptions.useServicePlanId?'':'zt.'}${region}.sms.api.sinch.com`;
Expand Down
6 changes: 3 additions & 3 deletions packages/sms/tests/rest/v1/sms-api.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Region, ServicePlanIdCredentials, UnifiedCredentials } from '../../../src';
import { SmsRegion, ServicePlanIdCredentials, UnifiedCredentials } from '../../../src';
import { SmsDomainApi } from '../../../src/rest/v1/sms-domain-api';
import { ApiHostname } from '@sinch/sdk-client';

Expand Down Expand Up @@ -37,7 +37,7 @@ describe('SMS API', () => {
});

it('should change the URL when specifying a different region', () => {
paramsWithServicePlanId.region = Region.CANADA;
paramsWithServicePlanId.smsRegion = SmsRegion.CANADA;
smsApi = new SmsDomainApi(paramsWithServicePlanId, 'dummy');
smsApi.getSinchClient();
expect(smsApi.client?.apiClientOptions.hostname).toBe('https://ca.sms.api.sinch.com');
Expand Down Expand Up @@ -93,7 +93,7 @@ describe('SMS API', () => {
expect(smsApi.client?.apiClientOptions.hostname).toBe('https://zt.us.sms.api.sinch.com');
smsApi.setCredentials({
...paramsWithServicePlanId,
region: Region.BRAZIL,
smsRegion: SmsRegion.BRAZIL,
});
expect(smsApi.client?.apiClientOptions.projectId).toBe('SERVICE_PLAN_ID');
expect(smsApi.client?.apiClientOptions.hostname).toBe('https://br.sms.api.sinch.com');
Expand Down

0 comments on commit 93179be

Please sign in to comment.