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 c52f832f7..598ed8729 100644 --- a/packages/swr-openapi/src/query-base.ts +++ b/packages/swr-openapi/src/query-base.ts @@ -1,9 +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 { TypesForGetRequest } from "./types.js"; +import type { TypesForRequest } from "./types.js"; + +export type DataHttpMethod = Extract; /** * @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 DataHttpMethod = "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; }