@risemaxi/api-client
Version:
Client Library for Rise
178 lines (177 loc) • 6.08 kB
JavaScript
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);
}