Files
core_ng/server/api/defs.ts
T
2023-08-18 14:13:46 +00:00

199 lines
8.6 KiB
TypeScript

import type { Request, Response } from 'express';
import type { Callable, DefAPINamespace, DeleteAPICallT, GetAPICallT, HeadAPICallT, HttpMethod, InvalidResponse, PatchAPICallT, PostAPICallT, PutAPICallT, RawArgType, ValidResponse, recoveryMethod } from '../apiStructure/defs.js';
import type { Empty, PostProcDecoratorRunner, ProcDecoratorRunner } from '../ProcDecorator/base.js';
import type { ZodType } from 'zod';
export type APINamespace = {
[key: string]: APINamespace
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| iAPI_GET<any, any, any, any>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| iAPI_POST<any, any, any, any>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| iAPI_PUT<any, any, any, any>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| iAPI_DELETE<any, any, any, any>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| iAPI_PATCH<any, any, any, any>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| iAPI_HEAD<any, any, any, any>
;
}
type ValidatorType<T> = T extends undefined ? undefined : ZodType<T>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type AnyAPIExecuter = APIExecuter<any, any, any, any>;
interface APIExecuter<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, CTX extends object> {
(query: Q, ctx: CTX, expressReq: Request, expressRes: Response): Promise<R | E | true>;
httpMethod: HttpMethod;
argValidator?: ValidatorType<Q>;
preDecorator: ProcDecoratorRunner<CTX, Empty>;
postDecorator: PostProcDecoratorRunner<CTX>;
}
export interface iAPI_GET<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, CTX extends object> extends APIExecuter<R, E, Q, CTX> {
httpMethod: 'get';
}
export interface iAPI_POST<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, CTX extends object> extends APIExecuter<R, E, Q, CTX> {
httpMethod: 'post';
}
export interface iAPI_PUT<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, CTX extends object> extends APIExecuter<R, E, Q, CTX> {
httpMethod: 'put';
}
export interface iAPI_DELETE<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, CTX extends object> extends APIExecuter<R, E, Q, CTX> {
httpMethod: 'delete';
}
export interface iAPI_PATCH<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, CTX extends object> extends APIExecuter<R, E, Q, CTX> {
httpMethod: 'patch';
}
export interface iAPI_HEAD<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, CTX extends object> extends APIExecuter<R, E, Q, CTX> {
httpMethod: 'head';
}
function generateAPI<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, CTX extends object>(httpMethod: HttpMethod,
argValidator: ValidatorType<Q> | undefined,
preDecorator: ProcDecoratorRunner<CTX, Empty>,
postDecorator: PostProcDecoratorRunner<CTX>,
callback: (query: Q, ctx: CTX, expressReq: Request, expressRes: Response) => Promise<R | E | true>,
): APIExecuter<R, E, Q, CTX> {
return Object.assign(
callback,
{
httpMethod,
argValidator,
preDecorator,
postDecorator,
}
);
}
export function GET<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
return <CTX extends object>([preDecorator, postDecorator]: readonly [ProcDecoratorRunner<CTX, Empty>, PostProcDecoratorRunner<CTX>]) => {
return (callback: (query: Q, ctx: CTX, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
return generateAPI<R, E, Q, CTX>(
'get',
argValidator,
preDecorator,
postDecorator,
callback,
) as iAPI_GET<R, E, Q, CTX>;
}
}
}
export function POST<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
return <CTX extends object>([preDecorator, postDecorator]: readonly [ProcDecoratorRunner<CTX, Empty>, PostProcDecoratorRunner<CTX>]) => {
return (callback: (query: Q, ctx: CTX, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
return generateAPI<R, E, Q, CTX>(
'post',
argValidator,
preDecorator,
postDecorator,
callback,
) as iAPI_POST<R, E, Q, CTX>;
}
}
}
export function PUT<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
return <CTX extends object>([preDecorator, postDecorator]: readonly [ProcDecoratorRunner<CTX, Empty>, PostProcDecoratorRunner<CTX>]) => {
return (callback: (query: Q, ctx: CTX, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
return generateAPI<R, E, Q, CTX>(
'put',
argValidator,
preDecorator,
postDecorator,
callback,
) as iAPI_PUT<R, E, Q, CTX>;
}
}
}
export function DELETE<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
return <CTX extends object>([preDecorator, postDecorator]: readonly [ProcDecoratorRunner<CTX, Empty>, PostProcDecoratorRunner<CTX>]) => {
return (callback: (query: Q, ctx: CTX, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
return generateAPI<R, E, Q, CTX>(
'delete',
argValidator,
preDecorator,
postDecorator,
callback,
) as iAPI_DELETE<R, E, Q, CTX>;
}
}
}
export function PATCH<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
return <CTX extends object>([preDecorator, postDecorator]: readonly [ProcDecoratorRunner<CTX, Empty>, PostProcDecoratorRunner<CTX>]) => {
return (callback: (query: Q, ctx: CTX, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
return generateAPI<R, E, Q, CTX>(
'patch',
argValidator,
preDecorator,
postDecorator,
callback,
) as iAPI_PATCH<R, E, Q, CTX>;
}
}
}
export function HEAD<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
return <CTX extends object>([preDecorator, postDecorator]: readonly [ProcDecoratorRunner<CTX, Empty>, PostProcDecoratorRunner<CTX>]) => {
return (callback: (query: Q, ctx: CTX, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
return generateAPI<R, E, Q, CTX>(
'head',
argValidator,
preDecorator,
postDecorator,
callback,
) as iAPI_HEAD<R, E, Q, CTX>;
}
}
}
export function raiseError(reason: string, recovery?: recoveryMethod): InvalidResponse {
if (recovery) {
return {
result: false,
reason,
recovery,
};
}
return {
result: false,
reason,
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ClassType<T> = new (...args: any[]) => T;
export type APIServerType<T extends Callable> =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends GetAPICallT<infer Q, infer R, infer E> ? iAPI_GET<R, E, Q, any> :
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends PostAPICallT<infer Q, infer R, infer E> ? iAPI_POST<R, E, Q, any> :
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends PutAPICallT<infer Q, infer R, infer E> ? iAPI_PUT<R, E, Q, any> :
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends DeleteAPICallT<infer Q, infer R, infer E> ? iAPI_DELETE<R, E, Q, any> :
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends PatchAPICallT<infer Q, infer R, infer E> ? iAPI_PATCH<R, E, Q, any> :
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends HeadAPICallT<infer Q, infer R, infer E> ? iAPI_HEAD<R, E, Q, any> :
never;
export type APINamespaceType<T extends DefAPINamespace> = {
[K in keyof T]:
T[K] extends Callable ? APIServerType<T[K]> :
T[K] extends DefAPINamespace ? APINamespaceType<T[K]> :
never;
};