From 147b57d446d60bb9daa95afca9e6a88f80724de7 Mon Sep 17 00:00:00 2001 From: Arthur Kozubov Date: Wed, 22 Oct 2025 15:06:53 +0200 Subject: [PATCH 1/2] feat: make able to provide fetch method in swr hook --- packages/swr-openapi/src/query-base.ts | 31 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/swr-openapi/src/query-base.ts b/packages/swr-openapi/src/query-base.ts index c52f832f7..6e1b37b0d 100644 --- a/packages/swr-openapi/src/query-base.ts +++ b/packages/swr-openapi/src/query-base.ts @@ -3,7 +3,9 @@ import type { MediaType, PathsWithMethod, RequiredKeysOf } from "openapi-typescr import { useCallback, useDebugValue, useMemo } from "react"; import type { Fetcher, SWRHook } from "swr"; import type { Exact } from "type-fest"; -import type { TypesForGetRequest } from "./types.js"; +import type { TypesForRequest } from "./types.js"; + +type HttpMethod = "get" | "post" | "put"; /** * @private @@ -16,27 +18,38 @@ export function configureBaseQueryHook(useHook: SWRHook) { FetcherError = never, >(client: Client, prefix: Prefix) { return function useQuery< - Path extends PathsWithMethod, - R extends TypesForGetRequest, + Path extends PathsWithMethod, + R extends TypesForRequest, Path>, Init extends Exact, Data extends R["Data"], Error extends R["Error"] | FetcherError, Config extends R["SWRConfig"], + M extends HttpMethod = "get", >( path: Path, - ...[init, config]: RequiredKeysOf extends never ? [(Init | null)?, Config?] : [Init | null, Config?] + ...[init, config]: RequiredKeysOf extends never + ? [((Init & { method?: M }) | null)?, Config?] + : [(Init & { method?: M }) | null, Config?] ) { useDebugValue(`${prefix} - ${path as string}`); - const key = useMemo(() => (init !== null ? ([prefix, path, init] as const) : null), [prefix, path, init]); + const key = useMemo( + () => (init !== null ? ([prefix, path, init] as const) : null), // @ts-ignore + [prefix, path, init], + ); type Key = typeof key; - // TODO: Lift up fetcher to and remove useCallback const fetcher: Fetcher = useCallback( - async ([_, path, init]) => { - // @ts-expect-error TODO: Improve internal init types - const res = await client.GET(path, init); + async ([, path, init]) => { + // runtime method default to 'get' + const method = ((init as any)?.method ?? "get") as HttpMethod; + const fn = client[method.toUpperCase() as Uppercase] as any; + if (!fn) { + throw new Error(`Unsupported method: ${method}`); + } + + const res = await fn(path, init); if (res.error) { throw res.error; } From f6046ca13b7bd4d86ec9e13615627b2aae82aace Mon Sep 17 00:00:00 2001 From: Arthur Kozubov Date: Thu, 23 Oct 2025 09:45:31 +0200 Subject: [PATCH 2/2] fix: types with providing optional method for mutate TODO: fix type --- packages/swr-openapi/src/mutate.ts | 17 ++++++++++------- packages/swr-openapi/src/query-base.ts | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/swr-openapi/src/mutate.ts b/packages/swr-openapi/src/mutate.ts index d69b11099..9ea81daf1 100644 --- a/packages/swr-openapi/src/mutate.ts +++ b/packages/swr-openapi/src/mutate.ts @@ -3,7 +3,8 @@ import type { MediaType, PathsWithMethod } from "openapi-typescript-helpers"; import { useCallback, useDebugValue } from "react"; import { type MutatorCallback, type MutatorOptions, useSWRConfig } from "swr"; import type { Exact, PartialDeep } from "type-fest"; -import type { TypesForGetRequest } from "./types.js"; +import type { TypesForRequest } from "./types.js"; +import type { DataHttpMethod } from "./query-base.js"; // Types are loose here to support ecosystem utilities like `_.isMatch` export type CompareFn = (init: any, partialInit: any) => boolean; @@ -46,15 +47,17 @@ export function createMutateHook return useCallback( function mutate< - Path extends PathsWithMethod, - R extends TypesForGetRequest, + Path extends PathsWithMethod, + R extends TypesForRequest, Path>, Init extends Exact, + Data extends R["Data"], + M extends DataHttpMethod = "get", >( - [path, init]: [Path, PartialDeep?], - data?: R["Data"] | Promise | MutatorCallback, - opts?: boolean | MutatorOptions, + [path, init]: [Path, (PartialDeep & { method?: M })?], + data?: Data | Promise | MutatorCallback, + opts?: boolean | (MutatorOptions), ) { - return swrMutate( + return swrMutate( (key) => { if ( // Must be array diff --git a/packages/swr-openapi/src/query-base.ts b/packages/swr-openapi/src/query-base.ts index 6e1b37b0d..598ed8729 100644 --- a/packages/swr-openapi/src/query-base.ts +++ b/packages/swr-openapi/src/query-base.ts @@ -1,11 +1,11 @@ import type { Client } from "openapi-fetch"; -import type { MediaType, PathsWithMethod, RequiredKeysOf } from "openapi-typescript-helpers"; +import type {HttpMethod, MediaType, PathsWithMethod, RequiredKeysOf} from "openapi-typescript-helpers"; import { useCallback, useDebugValue, useMemo } from "react"; import type { Fetcher, SWRHook } from "swr"; import type { Exact } from "type-fest"; import type { TypesForRequest } from "./types.js"; -type HttpMethod = "get" | "post" | "put"; +export type DataHttpMethod = Extract; /** * @private @@ -24,7 +24,7 @@ export function configureBaseQueryHook(useHook: SWRHook) { Data extends R["Data"], Error extends R["Error"] | FetcherError, Config extends R["SWRConfig"], - M extends HttpMethod = "get", + M extends DataHttpMethod = "get", >( path: Path, ...[init, config]: RequiredKeysOf extends never