Skip to content

Commit

Permalink
First draft of timeout parameter functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
diogob committed May 15, 2024
1 parent 2005601 commit 7123cea
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 5 deletions.
16 changes: 16 additions & 0 deletions src/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,22 @@ describe('makeFetcher', () => {
})
})

it('should accept a timeout in ms', async () => {
vi.spyOn(global, 'fetch').mockImplementationOnce(
async (_input: URL | RequestInfo, _init?: RequestInit | undefined) => {
await new Promise((r) => setTimeout(r, 2000))
return new Response(JSON.stringify({ foo: 'bar' }))
},
)
const service = subject.makeFetcher('https://example.com/api', {
timeout: 1,
})
await expect(() =>
service('/users', { method: 'post' }).then((r) => r.json()),
).rejects.toThrowError()
expect(reqMock).not.toHaveBeenCalled()
})

it('should add headers to the request', async () => {
vi.spyOn(global, 'fetch').mockImplementationOnce(
successfulFetch({ foo: 'bar' }),
Expand Down
25 changes: 20 additions & 5 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ function makeFetcher(baseURL: string | URL, baseOptions: BaseOptions = {}) {
path: T,
requestInit: EnhancedRequestInit<T> = {},
) => {
const { headers } = baseOptions
const { headers, timeout } = baseOptions
const requestTransformer = baseOptions.requestTransformer ?? identity
const responseTransformer = baseOptions.responseTransformer ?? identity
const headerTransformer = async (ri: EnhancedRequestInit) => ({
Expand All @@ -123,10 +123,25 @@ function makeFetcher(baseURL: string | URL, baseOptions: BaseOptions = {}) {
})

const url = makeGetApiURL(baseURL)(path)
const response = await enhancedFetch(
url,
await headerTransformer(await requestTransformer(requestInit)),
)
const fetchPromise = async () =>
enhancedFetch(
url,
await headerTransformer(await requestTransformer(requestInit)),
)

const throwOnTimeout = (timeout: number) =>
new Promise((_, reject) =>
setTimeout(
() => reject(new Error(`Timed out (${timeout}ms) fetching ${url}`)),
timeout,
),
)

const response = (await (timeout == undefined
? fetchPromise()
: Promise.race([fetchPromise(), throwOnTimeout(timeout)]))) as Awaited<
ReturnType<typeof fetchPromise>
>
return responseTransformer(response)
}
}
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type BaseOptions = {
headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>)
requestTransformer?: RequestTransformer
responseTransformer?: ResponseTransformer
timeout?: number
}

type HTTPMethod = (typeof HTTP_METHODS)[number]
Expand Down

0 comments on commit 7123cea

Please sign in to comment.