Skip to content

Commit

Permalink
feat: add proxy client (#257)
Browse files Browse the repository at this point in the history
  • Loading branch information
lcschy committed Dec 27, 2022
1 parent 9b3c0b4 commit c57e7f0
Show file tree
Hide file tree
Showing 15 changed files with 538 additions and 4 deletions.
14 changes: 14 additions & 0 deletions src/BasisTheory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
Tokenize as ElementsTokenize,
TokenizeData as ElementsTokenizeData,
Tokens as ElementsTokens,
Proxy as ElementsProxy,
} from '@/types/elements';
import type { TokenizeData } from '@/types/models';
import type {
Expand All @@ -35,6 +36,7 @@ import type {
BasisTheoryInitOptionsWithoutElements,
BasisTheoryInitStatus,
Proxies,
Proxy,
} from '@/types/sdk';
import { BasisTheoryApplications } from './applications';
import {
Expand All @@ -48,6 +50,7 @@ import { ELEMENTS_INIT_ERROR_MESSAGE } from './elements/constants';
import { BasisTheoryLogs } from './logs';
import { BasisTheoryPermissions } from './permissions';
import { BasisTheoryProxies } from './proxies';
import { BasisTheoryProxy } from './proxy';
import { BasisTheoryReactorFormulas } from './reactor-formulas';
import { BasisTheoryReactors } from './reactors';
import { BasisTheoryTenants } from './tenants';
Expand Down Expand Up @@ -84,6 +87,8 @@ export class BasisTheory

private _proxies?: Proxies;

private _proxy?: Proxy & ElementsProxy;

public init(
apiKey: string | undefined,
options?: BasisTheoryInitOptionsWithoutElements
Expand Down Expand Up @@ -179,6 +184,11 @@ export class BasisTheory
baseURL: new URL(CLIENT_BASE_PATHS.proxies, baseUrl).toString(),
appInfo,
});
this._proxy = new BasisTheoryProxy({
apiKey,
baseURL: new URL(CLIENT_BASE_PATHS.proxy, baseUrl).toString(),
appInfo,
});

this._initStatus = 'done';
} catch (error) {
Expand Down Expand Up @@ -296,6 +306,10 @@ export class BasisTheory
return assertInit(this._proxies);
}

public get proxy(): Proxy {
return assertInit(this._proxy);
}

/* eslint-enable accessor-pairs */

/**
Expand Down
1 change: 1 addition & 0 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const CLIENT_BASE_PATHS: BasisTheoryServicesBasePathMap = {
reactors: 'reactors',
permissions: 'permissions',
proxies: 'proxies',
proxy: 'proxy',
};

const BROWSER_LIST = [
Expand Down
12 changes: 10 additions & 2 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { Reactor, Proxy, Token, TokenBase } from '@/types/models';
import type {
ApplicationInfo,
ClientUserAgent,
ProxyRequestOptions,
RequestOptions,
} from '@/types/sdk';
import { BasisTheoryApiError } from './BasisTheoryApiError';
Expand Down Expand Up @@ -196,7 +197,7 @@ const concatResponseTransformerWithDefault = (
];

const createRequestConfig = (
options?: RequestOptions,
options?: ProxyRequestOptions | RequestOptions,
transformers?: RequestTransformers
): AxiosRequestConfig | undefined => {
if (!options) {
Expand All @@ -222,7 +223,12 @@ const createRequestConfig = (
};
}

const { apiKey, correlationId } = options;
const {
apiKey,
correlationId,
query,
headers,
} = options as ProxyRequestOptions;
const apiKeyHeader = apiKey
? {
[API_KEY_HEADER]: apiKey,
Expand All @@ -238,7 +244,9 @@ const createRequestConfig = (
headers: {
...apiKeyHeader,
...correlationIdHeader,
...(typeof headers !== 'undefined' && { ...headers }),
},
...(typeof query !== 'undefined' && { params: query }),
...(transformers?.transformRequest !== undefined
? {
transformRequest: concatRequestTransformerWithDefault(
Expand Down
57 changes: 57 additions & 0 deletions src/elements/services/proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { BasisTheoryProxy } from '@/proxy';
import type {
Proxy as ElementsProxy,
BasisTheoryElementsInternal,
} from '@/types/elements';
import type { Proxy, ProxyRequestOptions } from '@/types/sdk';

const delegateProxy = (
elements?: BasisTheoryElementsInternal
): new (
...args: ConstructorParameters<typeof BasisTheoryProxy>
) => ElementsProxy & Proxy =>
class BasisTheoryProxyElementsDelegate
extends BasisTheoryProxy
implements ElementsProxy {
public get(options?: ProxyRequestOptions): Promise<any> {
if (elements !== undefined) {
return elements.proxy.get(options);
}

return super.get(options);
}

public post(options?: ProxyRequestOptions): Promise<any> {
if (elements !== undefined) {
return elements.proxy.post(options);
}

return super.post(options);
}

public put(options?: ProxyRequestOptions): Promise<any> {
if (elements !== undefined) {
return elements.proxy.put(options);
}

return super.put(options);
}

public patch(options?: ProxyRequestOptions): Promise<any> {
if (elements !== undefined) {
return elements.proxy.patch(options);
}

return super.patch(options);
}

public delete(options?: ProxyRequestOptions): Promise<any> {
if (elements !== undefined) {
return elements.proxy.delete(options);
}

return super.delete(options);
}
};

export { delegateProxy };
51 changes: 51 additions & 0 deletions src/proxy/BasisTheoryProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { createRequestConfig, dataExtractor, proxyRaw } from '@/common';
import { BasisTheoryService } from '@/service';
import type { Proxy, ProxyRequestOptions } from '@/types/sdk';

type PROXY_METHODS = 'get' | 'post' | 'put' | 'patch' | 'delete';

export class BasisTheoryProxy extends BasisTheoryService implements Proxy {
public get(options?: ProxyRequestOptions): Promise<any> {
return this.proxyRequest('get', options);
}

public post(options?: ProxyRequestOptions): Promise<any> {
return this.proxyRequest('post', options);
}

public put(options?: ProxyRequestOptions): Promise<any> {
return this.proxyRequest('put', options);
}

public patch(options?: ProxyRequestOptions): Promise<any> {
return this.proxyRequest('patch', options);
}

public delete(options?: ProxyRequestOptions): Promise<any> {
return this.proxyRequest('delete', options);
}

private proxyRequest(
method: PROXY_METHODS,
options?: ProxyRequestOptions
): Promise<any> {
if (method === 'post' || method === 'put' || method === 'patch') {
return this.client[method](
options?.path ?? '/',
options?.body ?? undefined,
createRequestConfig(options, {
transformRequest: proxyRaw,
transformResponse: proxyRaw,
})
).then(dataExtractor);
}

return this.client[method](
options?.path ?? '/',
createRequestConfig(options, {
transformRequest: proxyRaw,
transformResponse: proxyRaw,
})
).then(dataExtractor);
}
}
1 change: 1 addition & 0 deletions src/proxy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './BasisTheoryProxy';
3 changes: 2 additions & 1 deletion src/types/elements/elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import type {
CardElementValue,
CardExpirationDateValue,
} from './options';
import type { Tokenize, Tokens } from './services';
import type { Tokenize, Tokens, Proxy } from './services';
import { DataElementReference } from './shared';

interface BaseElement<UpdateOptions, ElementEvents> {
Expand Down Expand Up @@ -86,6 +86,7 @@ type ElementValue =

interface BasisTheoryElements extends Tokenize {
tokens: Tokens;
proxy: Proxy;

createElement(type: 'card', options?: CreateCardElementOptions): CardElement;
createElement(type: 'text', options: CreateTextElementOptions): TextElement;
Expand Down
1 change: 1 addition & 0 deletions src/types/elements/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './tokenize';
export * from './tokens';
export * from './proxy';
11 changes: 11 additions & 0 deletions src/types/elements/services/proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { ProxyRequestOptions } from '@/types/sdk';

interface Proxy {
get(options?: ProxyRequestOptions): Promise<any>;
post(options?: ProxyRequestOptions): Promise<any>;
patch(options?: ProxyRequestOptions): Promise<any>;
put(options?: ProxyRequestOptions): Promise<any>;
delete(options?: ProxyRequestOptions): Promise<any>;
}

export type { Proxy };
2 changes: 2 additions & 0 deletions src/types/sdk/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
Reactors,
Permissions,
Proxies,
Proxy,
} from './services';

interface ApplicationInfo {
Expand Down Expand Up @@ -52,6 +53,7 @@ interface BasisTheory extends Tokenize {
reactors: Reactors;
permissions: Permissions;
proxies: Proxies;
proxy: Proxy;
}

interface ClientUserAgent {
Expand Down
1 change: 1 addition & 0 deletions src/types/sdk/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './reactor-formulas';
export * from './reactors';
export * from './permissions';
export * from './proxies';
export * from './proxy';
33 changes: 33 additions & 0 deletions src/types/sdk/services/proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { RequestOptions } from './shared';

interface Proxy {
get(options?: ProxyRequestOptions): Promise<any>;
post(options?: ProxyRequestOptions): Promise<any>;
patch(options?: ProxyRequestOptions): Promise<any>;
put(options?: ProxyRequestOptions): Promise<any>;
delete(options?: ProxyRequestOptions): Promise<any>;
}

type BasisTheoryProxyHeaders = {
[key: string]: string;
'BT-PROXY-URL': string;
'BT-PROXY-KEY': string;
};

type ProxyHeaders = Partial<BasisTheoryProxyHeaders>;

type BasisTheoryQueryParams = {
[key: string]: string;
'bt-proxy-key': string;
};

type ProxyQuery = Partial<BasisTheoryQueryParams>;

interface ProxyRequestOptions extends RequestOptions {
path?: string;
query?: ProxyQuery;
headers?: ProxyHeaders;
body?: unknown;
}

export type { Proxy, ProxyRequestOptions, ProxyHeaders, ProxyQuery };
6 changes: 5 additions & 1 deletion test/clients.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ describe('clients', () => {
...baseConfig,
baseURL: `${DEFAULT_BASE_URL}/${CLIENT_BASE_PATHS.proxies}`,
});
expect(create).toHaveBeenCalledTimes(9);
expect(create).toHaveBeenCalledWith({
...baseConfig,
baseURL: `${DEFAULT_BASE_URL}/${CLIENT_BASE_PATHS.proxy}`,
});
expect(create).toHaveBeenCalledTimes(10);
});

test('should throw error if not properly initialized', () => {
Expand Down

0 comments on commit c57e7f0

Please sign in to comment.