UNPKG

@rocketmakers/api-swr

Version:

Rocketmakers front-end library for parsing a generated Typescript API client into a set of configurable React hooks for fetching and mutating data.

122 lines (121 loc) 8.16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.genericApiControllerFactory = void 0; const tslib_1 = require("tslib"); const React = tslib_1.__importStar(require("react")); const useClientFetch_1 = require("../hooks/useClientFetch"); const useQuery_1 = require("../hooks/useQuery"); const caching_1 = require("../utils/caching"); const useInfiniteQuery_1 = require("../hooks/useInfiniteQuery"); const config_1 = require("../utils/config"); /** * Creates a factory of state management tools from a generic API controller object. * * @param {TConfig} globalFetchConfig - Optional custom fetch config to pass to all API calls. Can be overridden at endpoint and fetch level. * @param {boolean} options.enableMocking - Will use mock endpoint definitions instead of calling out to the real API. * @param {APIProcessingHook} options.useApiProcessing - Optional processing hook for all client side fetches. * @param {GlobalFetchWrapperHook<TConfig>} options.useGlobalFetchWrapper - Optional fetch wrapper hook for all client side fetches. * @param {SWRConfiguration<any | undefined>} options.swrConfig - Additional config to send to SWR for all queries. * @param {SWRInfiniteConfiguration<any | undefined>} options.swrInfiniteConfig - Additional config to send to SWR for all infinite loader queries. * @returns {IApiControllerFactory} A library of controller factory methods that create state management tools for a generic controller. */ const genericApiControllerFactory = ({ globalFetchConfig, enableMocking, useApiProcessing, useGlobalFetchWrapper, swrConfig, swrInfiniteConfig, } = {}) => { /** * Creates a set of state management tools from an OpenAPI controller * * @param controllerKey A name to use as the first part of the cache key for this controller, must be unique amongst all controllers * @param controller The controller object * @param controllerConfig Optional custom fetch config to pass to all API calls. Inherits global config and can be overridden at fetch level. * @returns A set of state management tools for an OpenAPI controller using Axios */ const createGenericApiController = (controllerKey, controller, controllerConfig) => { // Record of mock endpoints let registeredMockEndpoints = {}; /** * Merges the provided mock endpoints with the already registered mock endpoints. * @param mockEndpoints - An object containing mock endpoint functions. */ const registerMockEndpoints = (mockEndpoints) => { registeredMockEndpoints = Object.assign(Object.assign({}, registeredMockEndpoints), mockEndpoints); }; /** * Retrieves a mock endpoint function for a given endpoint key. * @param endpointKey - The key of the endpoint to retrieve the mock function for. * @returns The mock function for the given endpoint key. * @throws Will throw an error if a mock function for the given endpoint key has not been registered. */ const getMockEndpointFunction = (endpointKey) => { const mockFunc = registeredMockEndpoints[endpointKey]; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- this is nonsense, it's always defined if (!mockFunc) { throw new Error(`Mock endpoint not defined for: ${controllerKey}.${endpointKey}`); } return mockFunc; }; // iterate the controller object const endpoints = Object.keys(controller).reduce((memo, endpointKey) => { /** * Fetch function for server/client side use, calls the fetcher * @param args Whatever args have been passed to the fetch, this function doesn't need to know what they are * @returns The response data */ const fetchFactory = (enableMockingViaConfig) => (...args) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { if (enableMocking || enableMockingViaConfig) { const mockFunc = getMockEndpointFunction(endpointKey); return mockFunc(...args); } const func = controller[endpointKey]; return func(...args); }); /** * Retrieves the cache key for this specific endpoint * @param additionalCacheKey Any further cache key parts to add on to the default `controllerKey.endpointKey` * @returns The final cache key string for the endpoint */ const cacheKeyGetter = (additionalCacheKey) => { let finalKeys = Array.isArray(additionalCacheKey) ? additionalCacheKey : [additionalCacheKey]; finalKeys = finalKeys.filter((key) => key !== undefined && key !== null); return (0, caching_1.cacheKeyConcat)(controllerKey, endpointKey, ...finalKeys); }; /** * Returns a `swr` mutate matcher function which will invalidate on the basis of "starts with" on the root cache key * @param additionalCacheKey Any further cache key parts to add on to the default `controllerKey.endpointKey` * @returns A `swr` mutate matcher function */ const startsWithInvalidator = (additionalCacheKey) => { return (key) => { return typeof key === 'string' && key.startsWith(cacheKeyGetter(additionalCacheKey)); }; }; const endpointId = cacheKeyGetter(); /** * The combined state management tools for this endpoint */ const endpointTools = { controllerKey, endpointKey, endpointId: (0, caching_1.cacheKeyConcat)(controllerKey, endpointKey), fetch: (params, config) => { var _a; return fetchFactory()(params, (_a = (0, config_1.combineConfigs)({ fetchConfig: config }, globalFetchConfig, controllerConfig)) === null || _a === void 0 ? void 0 : _a.fetchConfig); }, cacheKey: cacheKeyGetter, startsWithInvalidator, useQuery: (config) => { const fetchOverride = React.useCallback((...args) => fetchFactory(config === null || config === void 0 ? void 0 : config.enableMocking)(...args), [fetchFactory]); return (0, useQuery_1.useQuery)(endpointId, fetchOverride, (0, config_1.combineConfigs)(config, globalFetchConfig, controllerConfig), useApiProcessing, useGlobalFetchWrapper, swrConfig); }, useMutation: (config) => { var _a; const fetchOverride = React.useCallback((...args) => fetchFactory(config === null || config === void 0 ? void 0 : config.enableMocking)(...args), [fetchFactory]); return (0, useClientFetch_1.useClientFetch)(endpointId, 'mutation', (_a = (0, config_1.combineConfigs)(config, globalFetchConfig, controllerConfig)) === null || _a === void 0 ? void 0 : _a.fetchConfig, fetchOverride, config === null || config === void 0 ? void 0 : config.params, useApiProcessing, useGlobalFetchWrapper, config === null || config === void 0 ? void 0 : config.fetchWrapper); }, useInfiniteQuery: (config) => { const fetchOverride = React.useCallback((...args) => fetchFactory(config === null || config === void 0 ? void 0 : config.enableMocking)(...args), [fetchFactory]); return (0, useInfiniteQuery_1.useInfiniteQuery)(endpointId, fetchOverride, (0, config_1.combineConfigs)(config, globalFetchConfig, controllerConfig), useApiProcessing, useGlobalFetchWrapper, swrInfiniteConfig); }, }; return Object.assign(Object.assign({}, memo), { [endpointKey]: endpointTools }); }, {}); return Object.assign(Object.assign({}, endpoints), { registerMockEndpoints }); }; return { createGenericApiController }; }; exports.genericApiControllerFactory = genericApiControllerFactory;