UNPKG

@risemaxi/api-client

Version:

Client Library for Rise

178 lines (177 loc) 6.08 kB
import { Value } from "@sinclair/typebox/value"; import { useInfiniteQuery, useMutation, useQuery, useQueryClient, } from "@tanstack/react-query"; import { EndpointByMethod, } from "./contract.js"; export class RiseApiClient { fetcher; #baseUrl = ""; #enabledParsing = true; constructor(fetcher) { this.fetcher = fetcher; } setBaseUrl(baseUrl) { this.#baseUrl = baseUrl; return this; } setEnableParsing(enable) { this.#enabledParsing = enable; return this; } #parse(schema, value) { return this.#enabledParsing ? Value.Parse(schema, value) : value; } #parseAsync(schema, value) { return value.then((res) => this.#parse(schema, res)); } #constructPath(template, params) { if (!params) { return template; } return template.replace(/{(\w+)}/g, (match, key) => { if (key in params) { return params[key]; } return match; }); } #request(method, path, ...params) { const parameters = params[0]; const finalPath = this.#constructPath(path, parameters?.path); const EndpointSchema = EndpointByMethod[method][path].properties; return this.#parseAsync(EndpointSchema.response, this.fetcher(method, this.#baseUrl + finalPath, this.#parse(EndpointSchema.parameters, parameters))); } get(path, ...params) { return this.#request("get", path, ...params); } post(path, ...params) { return this.#request("post", path, ...params); } patch(path, ...params) { return this.#request("patch", path, ...params); } delete(path, ...params) { return this.#request("delete", path, ...params); } put(path, ...params) { return this.#request("put", path, ...params); } } export function createRiseApiClient(fetcher) { return new RiseApiClient(fetcher); } export class RiseApiHooks { #client; constructor(client) { this.#client = client; } getCacheKey(method, path, // @ts-expect-error cannot seem to index with parameters ...params) { const key = `${method}_${path}`; return [key, ...params]; } setCachedData(queryClient, method, path, ...options) { const [data, ...params] = options; const queryKey = this.getCacheKey(method, path, ...params); queryClient.setQueryData(queryKey, data); } useSetCachedData(method, path, ...options) { const queryClient = useQueryClient(); this.setCachedData(queryClient, method, path, ...options); } getCachedData(queryClient, method, path, // @ts-expect-error cannot seem to index with parameters ...params) { const queryKey = this.getCacheKey(method, path, ...params); return queryClient.getQueryData(queryKey); } useGetCachedData(method, path, // @ts-expect-error cannot seem to index with parameters ...params) { const queryClient = useQueryClient(); return this.getCachedData(queryClient, method, path, ...params); } prefetchData(queryClient, path, ...rest) { const [config, options] = rest; const queryKey = this.getCacheKey("get", path, config); const queryFn = () => this.#client.get(path, config); queryClient.prefetchQuery({ ...options, queryKey, queryFn, }); } usePrefetchData(path, ...rest) { const queryClient = useQueryClient(); this.prefetchData(queryClient, path, ...rest); } useGet(path, ...rest) { const queryClient = useQueryClient(); const [config, options] = rest; const queryKey = this.getCacheKey("get", path, config); const invalidate = () => queryClient.invalidateQueries({ exact: true, queryKey, }); return Object.assign(useQuery({ queryFn: () => this.#client.get(path, config), queryKey, ...options, }), { invalidate, queryKey }); } useInfiniteGet(path, configMapper, options) { const queryClient = useQueryClient(); const queryKey = this.getCacheKey("get", path, configMapper({ meta: {}, queryKey: [], signal: new AbortController().signal, client: queryClient, })); const queryFn = (context) => { const config = configMapper(context); return this.#client.get(path, config); }; const invalidate = () => queryClient.invalidateQueries({ queryKey, }); return Object.assign(useInfiniteQuery({ queryFn, queryKey, ...options, }), { invalidate, queryKey }); } usePost(path, options) { const mutationKey = this.getCacheKey("post", path, {}); return Object.assign(useMutation({ mutationFn: (params) => this.#client.post(path, params), mutationKey, ...options, }), { mutationKey }); } usePatch(path, options) { const mutationKey = this.getCacheKey("patch", path, {}); return Object.assign(useMutation({ mutationFn: (params) => this.#client.patch(path, params), mutationKey, ...options, }), { mutationKey }); } useDelete(path, options) { const mutationKey = this.getCacheKey("delete", path, {}); return Object.assign(useMutation({ mutationFn: (params) => this.#client.delete(path, params), mutationKey, ...options, }), { mutationKey }); } usePut(path, options) { const mutationKey = this.getCacheKey("put", path, {}); return Object.assign(useMutation({ mutationFn: (params) => this.#client.put(path, params), mutationKey, ...options, }), { mutationKey }); } } export function createRiseApiHooks(client) { return new RiseApiHooks(client); }