swr-openapi
Version:
Generate SWR hooks from OpenAPI schemas
175 lines (168 loc) • 7.56 kB
TypeScript
import * as swr from 'swr';
import { SWRConfiguration, SWRResponse, MutatorCallback, MutatorOptions } from 'swr';
import * as openapi_fetch from 'openapi-fetch';
import { MaybeOptionalInit, FetchResponse, Client } from 'openapi-fetch';
import * as openapi_typescript_helpers from 'openapi-typescript-helpers';
import { PathsWithMethod, HttpMethod, MediaType, RequiredKeysOf } from 'openapi-typescript-helpers';
import * as swr_infinite from 'swr/infinite';
import { SWRInfiniteConfiguration, SWRInfiniteKeyLoader } from 'swr/infinite';
import { PartialDeep } from 'type-fest';
type MaybeRequired<T> = RequiredKeysOf<T> extends never ? T | undefined : T;
type TryKey<T, K extends PropertyKey> = T extends {
[Key in K]?: unknown;
} ? T[K] : undefined;
/**
* Provides specific types used within a given request
*/
type TypesForRequest<Paths extends Record<string | number, any>, Method extends Extract<HttpMethod, keyof Paths[keyof Paths]>, Path extends PathsWithMethod<Paths, Method>, Init = MaybeOptionalInit<Paths[Path], Method>, Params = Init extends {
params?: unknown;
} ? Init["params"] : undefined, Res = FetchResponse<Paths[Path][Method], Init, MediaType>, Data = Extract<Res, {
data: unknown;
}>["data"], Error = Extract<Res, {
error: unknown;
}>["error"], PathParams = TryKey<Params, "path">, Query = TryKey<Params, "query">, Headers = TryKey<Params, "header">, Cookies = TryKey<Params, "cookie">, SWRConfig = SWRConfiguration<Data, Error>> = {
Init: Init;
Data: Data;
Error: Error;
Path: MaybeRequired<PathParams>;
Query: MaybeRequired<Query>;
Headers: MaybeRequired<Headers>;
Cookies: Cookies;
SWRConfig: SWRConfig;
SWRResponse: SWRResponse<Data, Error, SWRConfig>;
};
/**
* Provides specific types for GET requests
*
* Uses {@link TypesForRequest}
*/
type TypesForGetRequest<Paths extends Record<string | number, any>, Path extends PathsWithMethod<Paths, Extract<"get", keyof Paths[keyof Paths]>>> = TypesForRequest<Paths, Extract<"get", keyof Paths[keyof Paths]>, Path>;
/**
* Produces a typed wrapper for [`useSWRImmutable`](https://swr.vercel.app/docs/revalidation.en-US#disable-automatic-revalidations).
*
* ```ts
* import createClient from "openapi-fetch";
* const client = createClient();
*
* const useImmutable = createImmutableHook(client, "<unique-key>");
*
* // Fetch the query
* useImmutable("/pets");
*
* // Skip the query
* useImmutable("/pets", null);
*
* // Fetch the query with parameters
* useImmutable("/pets", {
* params: { query: { limit: 10 } }
* });
*
* // Fetch the query with parameters and SWR configuration
* useImmutable(
* "/pets",
* { params: { query: { limit: 10 } } },
* { errorRetryCount: 2 },
* );
*
* // Fetch the query with no parameters and SWR configuration
* useImmutable(
* "/pets",
* {},
* { errorRetryCount: 2 },
* );
* ```
*/
declare const createImmutableHook: <Paths extends {}, IMediaType extends openapi_typescript_helpers.MediaType, Prefix extends string, FetcherError = never>(client: openapi_fetch.Client<Paths, IMediaType>, prefix: Prefix) => <Path extends openapi_typescript_helpers.PathsWithMethod<Paths, "get">, R extends TypesForGetRequest<Paths, Path>, Init extends R["Init"], Data extends R["Data"], Error extends R["Error"] | FetcherError, Config extends R["SWRConfig"]>(path: Path, ...[init, config]: openapi_typescript_helpers.RequiredKeysOf<Init> extends never ? [(Init | null)?, Config?] : [Init | null, Config?]) => swr.SWRResponse<Data, Error, swr.SWRConfiguration<Data_1, Error_1, swr.Fetcher<Data_1, SWRKey>> | undefined>;
/**
* Produces a typed wrapper for [`useSWRInfinite`](https://swr.vercel.app/docs/pagination#useswrinfinite).
*
* ```ts
* import createClient from "openapi-fetch";
* const client = createClient();
*
* const useInfinite = createInfiniteHook(client, "<unique-key>");
*
* useInfinite("/pets", (index, previousPage) => {
* if (previousPage && !previousPage.hasMore) {
* return null;
* }
*
* return {
* params: {
* query: {
* limit: 10,
* offset: index * 10,
* },
* },
* };
* });
* ```
*/
declare function createInfiniteHook<Paths extends {}, IMediaType extends MediaType, Prefix extends string, FetcherError = never>(client: Client<Paths, IMediaType>, prefix: Prefix): <Path extends PathsWithMethod<Paths, "get">, R extends TypesForGetRequest<Paths, Path>, Init extends R["Init"], Data extends R["Data"], Error extends R["Error"] | FetcherError, Config extends SWRInfiniteConfiguration<Data, Error>>(path: Path, getInit: SWRInfiniteKeyLoader<Data, Init | null>, config?: Config) => swr_infinite.SWRInfiniteResponse<Data, Error>;
type CompareFn = (init: any, partialInit: any) => boolean;
/**
* Produces a typed wrapper for [`useSWRConfig#mutate`](https://swr.vercel.app/docs/mutation).
*
* ```ts
* import createClient from "openapi-fetch";
* import { isMatch } from "lodash";
*
* const client = createClient();
*
* const useMutate = createMutateHook(client, "<unique-key>", isMatch);
*
* const mutate = useMutate();
*
* // Revalidate all keys matching this path
* await mutate(["/pets"]);
* await mutate(["/pets"], newData);
* await mutate(["/pets"], undefined, { revalidate: true });
*
* // Revlidate all keys matching this path and this subset of options
* await mutate(
* ["/pets", { query: { limit: 10 } }],
* newData,
* { revalidate: false }
* );
* ```
*/
declare function createMutateHook<Paths extends {}, IMediaType extends MediaType>(client: Client<Paths, IMediaType>, prefix: string, compare: CompareFn): () => <Path extends PathsWithMethod<Paths, "get">, R extends TypesForGetRequest<Paths, Path>, Init extends R["Init"]>([path, init]: [Path, PartialDeep<Init>?], data?: R["Data"] | Promise<R["Data"]> | MutatorCallback<R["Data"]>, opts?: boolean | MutatorOptions<R["Data"]>) => Promise<(R["Data"] | undefined)[]>;
/**
* Produces a typed wrapper for [`useSWR`](https://swr.vercel.app/docs/api).
*
* ```ts
* import createClient from "openapi-fetch";
*
* const client = createClient();
*
* const useQuery = createQueryHook(client, "<unique-key>");
*
* // Fetch the query
* useQuery("/pets");
*
* // Skip the query
* useQuery("/pets", null);
*
* // Fetch the query with parameters
* useQuery("/pets", {
* params: { query: { limit: 10 } }
* });
*
* // Fetch the query with parameters and SWR configuration
* useQuery(
* "/pets",
* { params: { query: { limit: 10 } } },
* { errorRetryCount: 2 },
* );
*
* // Fetch the query with no parameters and SWR configuration
* useQuery(
* "/pets",
* {},
* { errorRetryCount: 2 },
* );
* ```
*/
declare const createQueryHook: <Paths extends {}, IMediaType extends openapi_typescript_helpers.MediaType, Prefix extends string, FetcherError = never>(client: openapi_fetch.Client<Paths, IMediaType>, prefix: Prefix) => <Path extends openapi_typescript_helpers.PathsWithMethod<Paths, "get">, R extends TypesForGetRequest<Paths, Path>, Init extends R["Init"], Data extends R["Data"], Error extends R["Error"] | FetcherError, Config extends R["SWRConfig"]>(path: Path, ...[init, config]: openapi_typescript_helpers.RequiredKeysOf<Init> extends never ? [(Init | null)?, Config?] : [Init | null, Config?]) => swr.SWRResponse<Data, Error, swr.SWRConfiguration<Data_1, Error_1, swr.Fetcher<Data_1, SWRKey>> | undefined>;
export { createImmutableHook, createInfiniteHook, createMutateHook, createQueryHook };
export type { CompareFn, TypesForGetRequest, TypesForRequest };