Skip to content

Commit 7d7bb0c

Browse files
feat(client): add support for endpoint-specific base URLs
1 parent 850a7da commit 7d7bb0c

File tree

3 files changed

+41
-4
lines changed

3 files changed

+41
-4
lines changed

src/core.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ export class APIPromise<T> extends Promise<T> {
184184

185185
export abstract class APIClient {
186186
baseURL: string;
187+
#baseURLOverridden: boolean;
187188
maxRetries: number;
188189
timeout: number;
189190
httpAgent: Agent | undefined;
@@ -193,18 +194,21 @@ export abstract class APIClient {
193194

194195
constructor({
195196
baseURL,
197+
baseURLOverridden,
196198
maxRetries = 5,
197199
timeout = 60000, // 1 minute
198200
httpAgent,
199201
fetch: overriddenFetch,
200202
}: {
201203
baseURL: string;
204+
baseURLOverridden: boolean;
202205
maxRetries?: number | undefined;
203206
timeout: number | undefined;
204207
httpAgent: Agent | undefined;
205208
fetch: Fetch | undefined;
206209
}) {
207210
this.baseURL = baseURL;
211+
this.#baseURLOverridden = baseURLOverridden;
208212
this.maxRetries = validatePositiveInteger('maxRetries', maxRetries);
209213
this.timeout = validatePositiveInteger('timeout', timeout);
210214
this.httpAgent = httpAgent;
@@ -314,7 +318,7 @@ export abstract class APIClient {
314318
{ retryCount = 0 }: { retryCount?: number } = {},
315319
): { req: RequestInit; url: string; timeout: number } {
316320
const options = { ...inputOptions };
317-
const { method, path, query, headers: headers = {} } = options;
321+
const { method, path, query, defaultBaseURL, headers: headers = {} } = options;
318322

319323
const body =
320324
ArrayBuffer.isView(options.body) || (options.__binaryRequest && typeof options.body === 'string') ?
@@ -324,7 +328,7 @@ export abstract class APIClient {
324328
: null;
325329
const contentLength = this.calculateContentLength(body);
326330

327-
const url = this.buildURL(path!, query);
331+
const url = this.buildURL(path!, query, defaultBaseURL);
328332
if ('timeout' in options) validatePositiveInteger('timeout', options.timeout);
329333
options.timeout = options.timeout ?? this.timeout;
330334
const httpAgent = options.httpAgent ?? this.httpAgent ?? getDefaultAgent(url);
@@ -517,11 +521,12 @@ export abstract class APIClient {
517521
return new PagePromise<PageClass, Item>(this, request, Page);
518522
}
519523

520-
buildURL<Req>(path: string, query: Req | null | undefined): string {
524+
buildURL<Req>(path: string, query: Req | null | undefined, defaultBaseURL?: string | undefined): string {
525+
const baseURL = (!this.#baseURLOverridden && defaultBaseURL) || this.baseURL;
521526
const url =
522527
isAbsoluteURL(path) ?
523528
new URL(path)
524-
: new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
529+
: new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
525530

526531
const defaultQuery = this.defaultQuery();
527532
if (!isEmptyObj(defaultQuery)) {
@@ -806,6 +811,7 @@ export type RequestOptions<
806811
query?: Req | undefined;
807812
body?: Req | null | undefined;
808813
headers?: Headers | undefined;
814+
defaultBaseURL?: string | undefined;
809815

810816
maxRetries?: number;
811817
stream?: boolean | undefined;
@@ -828,6 +834,7 @@ const requestOptionsKeys: KeysEnum<RequestOptions> = {
828834
query: true,
829835
body: true,
830836
headers: true,
837+
defaultBaseURL: true,
831838

832839
maxRetries: true,
833840
stream: true,

src/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export class Together extends Core.APIClient {
182182

183183
super({
184184
baseURL: options.baseURL!,
185+
baseURLOverridden: baseURL ? baseURL !== 'https://api.together.xyz/v1' : false,
185186
timeout: options.timeout ?? 60000 /* 1 minute */,
186187
httpAgent: options.httpAgent,
187188
maxRetries: options.maxRetries,
@@ -206,6 +207,13 @@ export class Together extends Core.APIClient {
206207
endpoints: API.Endpoints = new API.Endpoints(this);
207208
hardware: API.Hardware = new API.Hardware(this);
208209

210+
/**
211+
* Check whether the base URL is set to its default.
212+
*/
213+
#baseURLOverridden(): boolean {
214+
return this.baseURL !== 'https://api.together.xyz/v1';
215+
}
216+
209217
/**
210218
* Query a reranker model
211219
*

tests/index.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,28 @@ describe('instantiate client', () => {
185185
const client = new Together({ apiKey: 'My API Key' });
186186
expect(client.baseURL).toEqual('https://api.together.xyz/v1');
187187
});
188+
189+
test('in request options', () => {
190+
const client = new Together({ apiKey: 'My API Key' });
191+
expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual(
192+
'http://localhost:5000/option/foo',
193+
);
194+
});
195+
196+
test('in request options overridden by client options', () => {
197+
const client = new Together({ apiKey: 'My API Key', baseURL: 'http://localhost:5000/client' });
198+
expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual(
199+
'http://localhost:5000/client/foo',
200+
);
201+
});
202+
203+
test('in request options overridden by env variable', () => {
204+
process.env['TOGETHER_BASE_URL'] = 'http://localhost:5000/env';
205+
const client = new Together({ apiKey: 'My API Key' });
206+
expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual(
207+
'http://localhost:5000/env/foo',
208+
);
209+
});
188210
});
189211

190212
test('maxRetries option is correctly set', () => {

0 commit comments

Comments
 (0)