From ae1d171ce38106e347fa47946df94eb1fb4e8773 Mon Sep 17 00:00:00 2001 From: Jean-Charles Fct Date: Sat, 25 Nov 2023 09:30:33 +0100 Subject: [PATCH] feat(request): add timeout (#7) Thanks to @jcfauchet for creating this PR! --- src/contexts.ts | 7 +++++-- src/qwikql-component.tsx | 3 +++ src/useMutation.ts | 23 ++++++++++++++++++++--- src/useQuery.ts | 20 ++++++++++++++++++-- 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/contexts.ts b/src/contexts.ts index bb33f7f..cbe5586 100644 --- a/src/contexts.ts +++ b/src/contexts.ts @@ -1,10 +1,13 @@ import { createContextId, QRL } from '@builder.io/qwik' export const QwikqlURLContext = createContextId<{ url: string }>('qwikql.url') +export const QwikqlTimeoutContext = createContextId<{ timeout: number }>( + 'qwikql.timeout' +) export const QwikqlRequestContextContext = createContextId<{ headers: Record }>('qwikql.requestContext') export const QwikqlSetHeadersContext = -createContextId) => void>>( + createContextId) => void>>( 'qwikql.setHeaders' - ) \ No newline at end of file + ) diff --git a/src/qwikql-component.tsx b/src/qwikql-component.tsx index 06aaa16..567f3fb 100644 --- a/src/qwikql-component.tsx +++ b/src/qwikql-component.tsx @@ -8,11 +8,13 @@ import { import { QwikqlRequestContextContext, QwikqlSetHeadersContext, + QwikqlTimeoutContext, QwikqlURLContext } from './contexts' interface QwikQLProps { url: string + timeout?: number headers?: Record } @@ -25,6 +27,7 @@ export const QwikQL = component$((props: QwikQLProps) => { useContextProvider(QwikqlURLContext, { url: props.url }) useContextProvider(QwikqlRequestContextContext, context) + useContextProvider(QwikqlTimeoutContext, { timeout: props.timeout }) useContextProvider( QwikqlSetHeadersContext, $((headers) => { diff --git a/src/useMutation.ts b/src/useMutation.ts index d95b345..e770b0e 100644 --- a/src/useMutation.ts +++ b/src/useMutation.ts @@ -1,6 +1,10 @@ import { $, useContext, useStore } from '@builder.io/qwik' import { request, RequestDocument } from 'graphql-request' -import { QwikqlRequestContextContext, QwikqlURLContext } from './contexts' +import { + QwikqlRequestContextContext, + QwikqlTimeoutContext, + QwikqlURLContext +} from './contexts' import { toQwikqlError } from './util/toQwikqlError' interface MutationStore { @@ -12,6 +16,8 @@ interface MutationStore { export const useMutation = (mutation: RequestDocument) => { const url = useContext(QwikqlURLContext).url const requestContext = useContext(QwikqlRequestContextContext) + const timeout = useContext(QwikqlTimeoutContext).timeout + const mutationAsString = mutation?.toString() const result = useStore({ data: undefined, @@ -21,17 +27,28 @@ export const useMutation = (mutation: RequestDocument) => { const mutate$ = $(async (variables: Record) => { result.loading = true + let controller: AbortController | undefined, timeoutId + if (timeout) { + controller = new AbortController() + timeoutId = setTimeout(() => { + controller!.abort() + }, timeout) + } + try { result.data = await request({ url, document: mutationAsString, variables, - requestHeaders: requestContext.headers + requestHeaders: requestContext.headers, + signal: controller?.signal }) } catch (error) { result.error = toQwikqlError(error) + } finally { + if (timeoutId) clearTimeout(timeoutId) + result.loading = false } - result.loading = false }) return { mutate$, result } diff --git a/src/useQuery.ts b/src/useQuery.ts index 5a791c2..8fab0f3 100644 --- a/src/useQuery.ts +++ b/src/useQuery.ts @@ -1,6 +1,10 @@ import { useContext, $ } from '@builder.io/qwik' import { request, RequestDocument } from 'graphql-request' -import { QwikqlRequestContextContext, QwikqlURLContext } from './contexts' +import { + QwikqlRequestContextContext, + QwikqlTimeoutContext, + QwikqlURLContext +} from './contexts' import { toQwikqlError } from './util/toQwikqlError' interface QueryConfig { @@ -11,17 +15,29 @@ export const useQuery = (query: RequestDocument) => { const queryAsString = query.toString() const url = useContext(QwikqlURLContext).url const requestContext = useContext(QwikqlRequestContextContext) + const timeout = useContext(QwikqlTimeoutContext).timeout const executeQuery$ = $(async (queryConfig: Partial = {}) => { + let controller: AbortController | undefined, timeoutId + if (timeout) { + controller = new AbortController() + timeoutId = setTimeout(() => { + controller!.abort() + }, timeout) + } + try { return await request({ url, document: queryAsString, variables: queryConfig.variables || undefined, - requestHeaders: requestContext.headers + requestHeaders: requestContext.headers, + signal: controller?.signal }) } catch (error) { return Promise.reject(toQwikqlError(error)) + } finally { + if (timeoutId) clearTimeout(timeoutId) } })