213 lines
8.8 KiB
TypeScript
213 lines
8.8 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';
|
|
import {
|
|
validate,
|
|
type ValidatorOptions,
|
|
} from "class-validator";
|
|
import { type ClassTransformOptions, plainToInstance } from "class-transformer";
|
|
import type { InvalidProc, ProcDecorator, ProcDecoratorChain, ResolveChain } from './ProcDecorator/base.js';
|
|
import { clamp } from 'lodash-es';
|
|
|
|
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 : ClassType<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, PD extends ProcDecoratorChain> {
|
|
(query: Q, ctx: ResolveChain<PD>, expressReq: Request, expressRes: Response): Promise<R | E | true>;
|
|
httpMethod: HttpMethod;
|
|
argValidator?: ValidatorType<Q>;
|
|
preDecorator: ProcDecorator<any, any>[];
|
|
postDecorator: (ProcDecorator<any, any> | undefined)[];
|
|
}
|
|
|
|
export interface iAPI_GET<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, PD extends ProcDecoratorChain> extends APIExecuter<R, E, Q, PD> {
|
|
httpMethod: 'get';
|
|
}
|
|
|
|
export interface iAPI_POST<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, PD extends ProcDecoratorChain> extends APIExecuter<R, E, Q, PD> {
|
|
httpMethod: 'post';
|
|
}
|
|
|
|
export interface iAPI_PUT<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, PD extends ProcDecoratorChain> extends APIExecuter<R, E, Q, PD> {
|
|
httpMethod: 'put';
|
|
}
|
|
|
|
export interface iAPI_DELETE<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, PD extends ProcDecoratorChain> extends APIExecuter<R, E, Q, PD> {
|
|
httpMethod: 'delete';
|
|
}
|
|
|
|
export interface iAPI_PATCH<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, PD extends ProcDecoratorChain> extends APIExecuter<R, E, Q, PD> {
|
|
httpMethod: 'patch';
|
|
}
|
|
|
|
export interface iAPI_HEAD<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, PD extends ProcDecoratorChain> extends APIExecuter<R, E, Q, PD> {
|
|
httpMethod: 'head';
|
|
}
|
|
|
|
function generateAPI<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType, PD extends ProcDecoratorChain>(httpMethod: HttpMethod,
|
|
argValidator: ValidatorType<Q> | undefined,
|
|
procDecoratorChain: PD,
|
|
callback: (query: Q, ctx: ResolveChain<PD>, expressReq: Request, expressRes: Response) => Promise<R | E | true>,
|
|
): APIExecuter<R, E, Q, PD> {
|
|
const preDecorator: ProcDecorator<any, any>[] = [];
|
|
const postDecorator: (ProcDecorator<any, any> | undefined)[] = [];
|
|
if (procDecoratorChain) {
|
|
for (const procGen of procDecoratorChain) {
|
|
const proc = procGen();
|
|
if (Array.isArray(proc)) {
|
|
preDecorator.push(proc[0]);
|
|
postDecorator.push(undefined);
|
|
}
|
|
else {
|
|
preDecorator.push(proc);
|
|
postDecorator.push(proc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Object.assign(
|
|
callback,
|
|
{
|
|
httpMethod,
|
|
argValidator,
|
|
preDecorator,
|
|
postDecorator,
|
|
}
|
|
);
|
|
}
|
|
|
|
export function GET<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
|
|
return <PD extends ProcDecoratorChain>(procDecoratorChain: PD) => {
|
|
return (callback: (query: Q, ctx: ResolveChain<PD>, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
|
|
return generateAPI<R, E, Q, PD>(
|
|
'get',
|
|
argValidator,
|
|
procDecoratorChain,
|
|
callback,
|
|
) as iAPI_GET<R, E, Q, PD>;
|
|
}
|
|
}
|
|
}
|
|
|
|
export function POST<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
|
|
return <PD extends ProcDecoratorChain>(procDecoratorChain: PD) => {
|
|
return (callback: (query: Q, ctx: ResolveChain<PD>, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
|
|
return generateAPI<R, E, Q, PD>(
|
|
'post',
|
|
argValidator,
|
|
procDecoratorChain,
|
|
callback,
|
|
) as iAPI_POST<R, E, Q, PD>;
|
|
}
|
|
}
|
|
}
|
|
|
|
export function PUT<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
|
|
return <PD extends ProcDecoratorChain>(procDecoratorChain: PD) => {
|
|
return (callback: (query: Q, ctx: ResolveChain<PD>, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
|
|
return generateAPI<R, E, Q, PD>(
|
|
'put',
|
|
argValidator,
|
|
procDecoratorChain,
|
|
callback,
|
|
) as iAPI_PUT<R, E, Q, PD>;
|
|
}
|
|
}
|
|
}
|
|
|
|
export function DELETE<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
|
|
return <PD extends ProcDecoratorChain>(procDecoratorChain: PD) => {
|
|
return (callback: (query: Q, ctx: ResolveChain<PD>, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
|
|
return generateAPI<R, E, Q, PD>(
|
|
'delete',
|
|
argValidator,
|
|
procDecoratorChain,
|
|
callback,
|
|
) as iAPI_DELETE<R, E, Q, PD>;
|
|
}
|
|
}
|
|
}
|
|
|
|
export function PATCH<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
|
|
return <PD extends ProcDecoratorChain>(procDecoratorChain: PD) => {
|
|
return (callback: (query: Q, ctx: ResolveChain<PD>, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
|
|
return generateAPI<R, E, Q, PD>(
|
|
'patch',
|
|
argValidator,
|
|
procDecoratorChain,
|
|
callback,
|
|
) as iAPI_PATCH<R, E, Q, PD>;
|
|
}
|
|
}
|
|
}
|
|
|
|
export function HEAD<R extends ValidResponse, E extends InvalidResponse, Q extends RawArgType>(argValidator?: ValidatorType<Q>) {
|
|
return <PD extends ProcDecoratorChain>(procDecoratorChain: PD) => {
|
|
return (callback: (query: Q, ctx: ResolveChain<PD>, expressReq: Request, expressRes: Response) => Promise<R | E | true>) => {
|
|
return generateAPI<R, E, Q, PD>(
|
|
'head',
|
|
argValidator,
|
|
procDecoratorChain,
|
|
callback,
|
|
) as iAPI_HEAD<R, E, Q, PD>;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}; |