Last active
August 1, 2024 13:57
-
-
Save AspireOne/d6727d1898ca3606241bbc206b37a299 to your computer and use it in GitHub Desktop.
Typesafe react-query wrapper for openapi-fetch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { | |
FetchError, | |
ResponseType, | |
MutationVariablesType, | |
PathsWithDefinedMethods, | |
} from "@/types/api-mutators"; | |
import { client } from "@/api/common"; | |
import { createApiMutation } from "@/helpers/create-api-mutation.helper"; | |
// NOTE: WILL NOT WORK WITH "PATH" arguments (if the target API endpoint is e.g. "/user/:id"). | |
export function createTypedApiMutation< | |
TMethod extends "post" | "patch" | "put" | "delete", | |
TPath extends PathsWithDefinedMethods<TMethod>, | |
>(method: TMethod, path: TPath) { | |
type Response = ResponseType<TPath, TMethod>; | |
type Variables = MutationVariablesType<TMethod, TPath>; | |
return createApiMutation<Response, Variables, FetchError>({ | |
mutationKey: [path, method], | |
mutationFn: async (variables) => { | |
const methodUpper = method.toUpperCase() as Uppercase<TMethod>; | |
// ? Throw error? | |
return (client as any) | |
// TODO(fix): Here, we should also somehow pass in "path" parameter. | |
[methodUpper](path, { body: variables ?? {} }) | |
.then((response: any) => response.data); | |
}, | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { HttpMethod } from "openapi-typescript-helpers"; | |
import type { | |
FetchError, | |
PathsWithDefinedMethods, | |
ResponseType, | |
VariablesType, | |
} from "@/types/api-mutators"; | |
import { client } from "@/api/common"; | |
import { createApiQuery } from "@/helpers/create-api-query.helper"; | |
import type { CreateQueryOptions } from "react-query-kit"; | |
type HttpMethodUppercase = Uppercase<HttpMethod>; | |
export function createTypedApiQuery< | |
TMethod extends "get" | "delete" | "options" | "head", | |
TPath extends PathsWithDefinedMethods<TMethod>, | |
TCustomResponse = ResponseType<TPath, TMethod>, | |
// prettier-ignore | |
TOptions = CreateQueryOptions<TCustomResponse, VariablesType<TPath, TMethod>, FetchError>, | |
>(method: TMethod, path: TPath, options?: TOptions) { | |
type Response = TCustomResponse; | |
type Variables = VariablesType<TPath, TMethod>; | |
const upperMethod = method.toUpperCase() as HttpMethodUppercase; | |
return createApiQuery<Response, Variables, FetchError>({ | |
queryKey: [path], | |
...options, | |
fetcher: async (variables) => { | |
return (client[upperMethod] as any)(path, { params: variables }).then( | |
(response: any) => response.data, | |
); | |
}, | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type FetchError = { | |
// For HTTP errors | |
response: Response; | |
message: string; | |
}; | |
export type DefaultStatusCode<M extends HttpMethod> = M extends "post" ? 201 : 200; | |
export type PathsWithDefinedMethods<M extends HttpMethod> = { | |
[K in keyof paths]: { | |
[P in M]: paths[K] extends { [key in P]: infer MethodType } | |
? MethodType extends never | |
? never | |
: K | |
: never; | |
}[M]; | |
}[keyof paths]; | |
// Updated ResponseType that allows manual status code specification and includes | undefined | |
export type ResponseType< | |
P extends keyof paths, | |
M extends HttpMethod, | |
S extends number = DefaultStatusCode<M>, | |
> = paths[P][M] extends { | |
responses: { [K in S]: { content: { "application/json": infer R } } }; | |
} | |
? R | undefined | |
: undefined; | |
export type VariablesType< | |
P extends keyof paths, | |
M extends HttpMethod, | |
> = paths[P][M] extends { | |
parameters: infer Params; | |
} | |
? (Params extends { query: infer Q } ? { query: Q } : {}) & | |
(Params extends { path: infer Path } ? { path: Path } : {}) | |
: never; | |
export type MutationVariablesType< | |
M extends HttpMethod, | |
P extends PathsWithDefinedMethods<M>, | |
> = paths[P][M] extends { | |
requestBody: infer Body; | |
} | |
? Body extends { content: infer C } | |
? C extends { "application/json": infer V } | |
? V | |
: never | |
: never | |
: never; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment