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}