Skip to content

Commit

Permalink
feat(client): allow overriding retry count header (#1098)
Browse files Browse the repository at this point in the history
  • Loading branch information
stainless-app[bot] authored and stainless-bot committed Sep 25, 2024
1 parent ecdb4e9 commit a466ff7
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 3 deletions.
18 changes: 15 additions & 3 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,11 @@ export abstract class APIClient {
delete reqHeaders['content-type'];
}

reqHeaders['x-stainless-retry-count'] = String(retryCount);
// Don't set the retry count header if it was already set or removed by the caller. We check `headers`,
// which can contain nulls, instead of `reqHeaders` to account for the removal case.
if (getHeader(headers, 'x-stainless-retry-count') === undefined) {
reqHeaders['x-stainless-retry-count'] = String(retryCount);
}

this.validateHeaders(reqHeaders, headers);

Expand Down Expand Up @@ -1170,7 +1174,15 @@ export const isHeadersProtocol = (headers: any): headers is HeadersProtocol => {
return typeof headers?.get === 'function';
};

export const getRequiredHeader = (headers: HeadersLike, header: string): string => {
export const getRequiredHeader = (headers: HeadersLike | Headers, header: string): string => {
const foundHeader = getHeader(headers, header);
if (foundHeader === undefined) {
throw new Error(`Could not find ${header} header`);
}
return foundHeader;
};

export const getHeader = (headers: HeadersLike | Headers, header: string): string | undefined => {
const lowerCasedHeader = header.toLowerCase();
if (isHeadersProtocol(headers)) {
// to deal with the case where the header looks like Stainless-Event-Id
Expand All @@ -1196,7 +1208,7 @@ export const getRequiredHeader = (headers: HeadersLike, header: string): string
}
}

throw new Error(`Could not find ${header} header`);
return undefined;
};

/**
Expand Down
58 changes: 58 additions & 0 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,64 @@ describe('retries', () => {
expect(count).toEqual(3);
});

test('omit retry count header', async () => {
let count = 0;
let capturedRequest: RequestInit | undefined;
const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise<Response> => {
count++;
if (count <= 2) {
return new Response(undefined, {
status: 429,
headers: {
'Retry-After': '0.1',
},
});
}
capturedRequest = init;
return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } });
};
const client = new OpenAI({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 });

expect(
await client.request({
path: '/foo',
method: 'get',
headers: { 'X-Stainless-Retry-Count': null },
}),
).toEqual({ a: 1 });

expect(capturedRequest!.headers as Headers).not.toHaveProperty('x-stainless-retry-count');
});

test('overwrite retry count header', async () => {
let count = 0;
let capturedRequest: RequestInit | undefined;
const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise<Response> => {
count++;
if (count <= 2) {
return new Response(undefined, {
status: 429,
headers: {
'Retry-After': '0.1',
},
});
}
capturedRequest = init;
return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } });
};
const client = new OpenAI({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 });

expect(
await client.request({
path: '/foo',
method: 'get',
headers: { 'X-Stainless-Retry-Count': '42' },
}),
).toEqual({ a: 1 });

expect((capturedRequest!.headers as Headers)['x-stainless-retry-count']).toBe('42');
});

test('retry on 429 with retry-after', async () => {
let count = 0;
const testFetch = async (url: RequestInfo, { signal }: RequestInit = {}): Promise<Response> => {
Expand Down

0 comments on commit a466ff7

Please sign in to comment.