repos / starfx

supercharged async flow control library.
git clone https://github.com/neurosnap/starfx.git

starfx / query
Eric Bower · 30 Jul 24

api.ts

 1// deno-lint-ignore-file no-explicit-any
 2import type { ApiCtx, ApiRequest } from "./types.ts";
 3import type { Next } from "../types.ts";
 4import { createThunks } from "./thunk.ts";
 5import type { ThunksApi } from "./thunk.ts";
 6import type { ApiName, QueryApi } from "./api-types.ts";
 7
 8/**
 9 * Creates a middleware thunksline for HTTP requests.
10 *
11 * @remarks
12 * It uses {@link createThunks} under the hood.
13 *
14 * @example
15 * ```ts
16 * import { createApi, mdw } from 'starfx';
17 *
18 * const api = createApi();
19 * api.use(mdw.api());
20 * api.use(api.routes());
21 * api.use(mdw.fetch({ baseUrl: 'https://api.com' }));
22 *
23 * const fetchUsers = api.get('/users', function*(ctx, next) {
24 *   yield next();
25 * });
26 *
27 * store.dispatch(fetchUsers());
28 * ```
29 */
30export function createApi<Ctx extends ApiCtx = ApiCtx>(
31  baseThunk?: ThunksApi<Ctx>,
32): QueryApi<Ctx> {
33  const thunks = baseThunk || createThunks<Ctx>();
34  const uri = (prename: ApiName) => {
35    const create = thunks.create as any;
36
37    let name = prename;
38    let remainder = "";
39    if (Array.isArray(name)) {
40      if (name.length === 0) {
41        throw new Error(
42          "createApi requires a non-empty array for the name of the endpoint",
43        );
44      }
45      name = prename[0];
46      if (name.length > 1) {
47        const [_, ...other] = prename;
48        remainder = ` ${other.join("|")}`;
49      }
50    }
51    const tmpl = (method: string) => `${name} [${method}]${remainder}`;
52
53    return {
54      get: (...args: any[]) => create(tmpl("GET"), ...args),
55      post: (...args: any[]) => create(tmpl("POST"), ...args),
56      put: (...args: any[]) => create(tmpl("PUT"), ...args),
57      patch: (...args: any[]) => create(tmpl("PATCH"), ...args),
58      delete: (...args: any[]) => create(tmpl("DELETE"), ...args),
59      options: (...args: any[]) => create(tmpl("OPTIONS"), ...args),
60      head: (...args: any[]) => create(tmpl("HEAD"), ...args),
61      connect: (...args: any[]) => create(tmpl("CONNECT"), ...args),
62      trace: (...args: any[]) => create(tmpl("TRACE"), ...args),
63    };
64  };
65
66  return {
67    use: thunks.use,
68    /**
69     * @deprecated use `register()` instead
70     */
71    bootup: thunks.register,
72    register: thunks.register,
73    create: thunks.create,
74    routes: thunks.routes,
75    reset: thunks.reset,
76    cache: () => {
77      return function* onCache(ctx: Ctx, next: Next) {
78        ctx.cache = true;
79        yield* next();
80      };
81    },
82    request: (req: ApiRequest) => {
83      return function* onRequest(ctx: Ctx, next: Next) {
84        ctx.request = ctx.req(req);
85        yield* next();
86      };
87    },
88    uri,
89    get: (name: ApiName, ...args: any[]) => uri(name).get(...args),
90    post: (name: ApiName, ...args: any[]) => uri(name).post(...args),
91    put: (name: ApiName, ...args: any[]) => uri(name).put(...args),
92    patch: (name: ApiName, ...args: any[]) => uri(name).patch(...args),
93    delete: (name: ApiName, ...args: any[]) => uri(name).delete(...args),
94    options: (name: ApiName, ...args: any[]) => uri(name).options(...args),
95    head: (name: ApiName, ...args: any[]) => uri(name).head(...args),
96    connect: (name: ApiName, ...args: any[]) => uri(name).connect(...args),
97    trace: (name: ApiName, ...args: any[]) => uri(name).trace(...args),
98  };
99}