1- import { IRouter , RequestHandler } from "express" ;
1+ import { IRouter , RequestHandler , Router } from "express" ;
22import {
33 Method ,
44 AnyApiResponses ,
55 ApiResBody ,
66 ApiSpec ,
7- AnyApiSpec ,
87 AnyApiEndpoints ,
98} from "../index" ;
109import {
@@ -15,9 +14,14 @@ import {
1514} from "express-serve-static-core" ;
1615import { StatusCode } from "../core" ;
1716import { ParsedQs } from "qs" ;
18- import { AnySpecValidator , SpecValidatorMap } from "../core/validator/request" ;
17+ import { AnySpecValidator } from "../core/validator/request" ;
1918import { StandardSchemaV1 } from "@standard-schema/spec" ;
20- import { newSSValidator , SSApiEndpoints } from "../core/ss" ;
19+ import {
20+ newSSValidator ,
21+ SSApiEndpoints ,
22+ ToApiEndpoints ,
23+ ToSSValidators ,
24+ } from "../core/ss" ;
2125
2226/**
2327 * Express Request Handler, but with more strict type information.
@@ -37,23 +41,64 @@ export type Handler<
3741) => void ;
3842
3943export type ToHandler <
40- Spec extends AnyApiSpec | undefined ,
41- Validators extends AnySpecValidator | undefined ,
44+ E extends SSApiEndpoints ,
45+ Path extends keyof E & string ,
46+ M extends Method ,
4247> = Handler <
43- Spec ,
48+ ToApiEndpoints < E > [ Path ] [ M ] ,
4449 ValidateLocals <
45- Validators extends AnySpecValidator ? Validators : Record < string , never >
50+ ToSSValidators < E , Path , M > extends AnySpecValidator
51+ ? ToSSValidators < E , Path , M >
52+ : Record < string , never >
4653 >
4754> ;
55+ // export type ToHandler<
56+ // Spec extends AnyApiSpec | undefined,
57+ // Validators extends AnySpecValidator | undefined,
58+ // > = Handler<
59+ // Spec,
60+ // ValidateLocals<
61+ // Validators extends AnySpecValidator ? Validators : Record<string, never>
62+ // >
63+ // >;
4864
49- export type ToHandlers <
50- E extends AnyApiEndpoints ,
51- V extends SpecValidatorMap ,
52- > = {
65+ /**
66+ * Convert ZodApiSpec to Express Request Handler type.
67+ */
68+ // export type ToHandler<
69+ // ZodE extends SSApiEndpoints,
70+ // Path extends keyof ZodE & string,
71+ // M extends Method,
72+ // > = ToPureHandler<ToApiEndpoints<ZodE>[Path][M], ToSSValidators<ZodE, Path, M>>;
73+
74+ export type ToHandlers < E extends SSApiEndpoints > = {
5375 [ Path in keyof E & string ] : {
54- [ M in Method ] : ToHandler < E [ Path ] [ M ] , V [ Path ] [ M ] > ;
76+ [ M in Method ] : ToHandler < E , Path , M > ;
5577 } ;
5678} ;
79+ // export type ToHandlers<
80+ // E extends AnyApiEndpoints,
81+ // V extends SpecValidatorMap,
82+ // > = {
83+ // [Path in keyof E & string]: {
84+ // [M in Method]: ToHandler<E[Path][M], V[Path][M]>;
85+ // };
86+ // };
87+
88+ /**
89+ * Convert SSApiEndpoints to Express Request Handler type map.
90+ */
91+ // export type ToHandlers<
92+ // ZodE extends SSApiEndpoints,
93+ // E extends ToApiEndpoints<ZodE> = ToApiEndpoints<ZodE>,
94+ // V extends ToValidatorsMap<ZodE> = ToValidatorsMap<ZodE>,
95+ // > = ToPureHandlers<E, V>;
96+
97+ // export type ToValidatorsMap<ESchema extends SSApiEndpoints> = {
98+ // [Path in keyof ESchema & string]: {
99+ // [M in Method]: ToSSValidators<ESchema, Path, M>;
100+ // };
101+ // };
57102
58103/**
59104 * Express Response, but with more strict type information.
@@ -80,7 +125,6 @@ export type ValidateLocals<
80125 */
81126export type RouterT <
82127 E extends AnyApiEndpoints ,
83- V extends SpecValidatorMap ,
84128 SC extends StatusCode = StatusCode ,
85129> = Omit < IRouter , Method > & {
86130 [ M in Method ] : < Path extends string & keyof E > (
@@ -89,9 +133,9 @@ export type RouterT<
89133 // Middlewareは複数のエンドポイントで実装を使い回されることがあるので、型チェックはゆるくする
90134 ...Array < RequestHandler > ,
91135 // Handlerは厳密に型チェックする
92- ToHandler < E [ Path ] [ M ] , V [ Path ] [ M ] > ,
136+ ToHandler < E , Path , M > ,
93137 ]
94- ) => RouterT < E , V , SC > ;
138+ ) => RouterT < E , SC > ;
95139} ;
96140
97141// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -212,3 +256,29 @@ export const asAsync = <Router extends IRouter | RouterT<any, any>>(
212256 } ,
213257 } ) ;
214258} ;
259+
260+ /**
261+ * Set validator and add more strict type information to router.
262+ *
263+ * @param pathMap API endpoints
264+ * @param router Express Router
265+ *
266+ * @example
267+ * ```
268+ * const router = typed(pathMap, express.Router())
269+ * router.get('/path', (req, res) => {
270+ * const {data, error} = res.locals.validate(req).query()
271+ * if (error) {
272+ * return res.status(400).json({ message: 'Invalid query' })
273+ * }
274+ * return res.status(200).json({ message: 'success', value: r.data.value })
275+ * })
276+ * ```
277+ */
278+ export const typed = < const Endpoints extends SSApiEndpoints > (
279+ pathMap : Endpoints ,
280+ router : Router ,
281+ ) : RouterT < Endpoints > => {
282+ router . use ( validatorMiddleware ( pathMap ) ) ;
283+ return router ;
284+ } ;
0 commit comments