Skip to content

Commit c81426a

Browse files
committed
Merge branch 'main' of github.com:muneebhashone/typescript-backend-toolkit into modules-separated
2 parents b4836bc + 9aa00f1 commit c81426a

File tree

2 files changed

+69
-57
lines changed

2 files changed

+69
-57
lines changed

src/config/config.service.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,31 @@ import { z } from 'zod';
33

44
dotenv.config();
55

6+
// Remove .optional() from requried schema properties
7+
68
const configSchema = z.object({
79
REDIS_URL: z.string().url(),
810
PORT: z.string().regex(/^\d+$/).transform(Number),
9-
DATABASE_URL: z.string().url(),
11+
DATABASE_URL: z.string().url().optional(),
1012
MONGO_DATABASE_URL: z.string().url(),
11-
SMTP_HOST: z.string().min(1),
12-
SMTP_PORT: z.string().regex(/^\d+$/).transform(Number),
13-
SMTP_USERNAME: z.string().email(),
14-
EMAIL_FROM: z.string().email(),
15-
SMTP_FROM: z.string().min(1),
16-
SMTP_PASSWORD: z.string().min(1),
13+
SMTP_HOST: z.string().min(1).optional(),
14+
SMTP_PORT: z.string().regex(/^\d+$/).transform(Number).optional(),
15+
SMTP_USERNAME: z.string().email().optional(),
16+
EMAIL_FROM: z.string().email().optional(),
17+
SMTP_FROM: z.string().min(1).optional(),
18+
SMTP_PASSWORD: z.string().min(1).optional(),
1719
CLIENT_SIDE_URL: z.string().url(),
1820
JWT_SECRET: z.string().min(1),
1921
JWT_EXPIRES_IN: z.string().regex(/^(\d+d|\d+h|\d+m|\d+s)$/),
2022
SESSION_EXPIRES_IN: z.string().min(1).transform(Number),
2123
PASSWORD_RESET_TOKEN_EXPIRES_IN: z.string().min(1).transform(Number),
2224
SET_PASSWORD_TOKEN_EXPIRES_IN: z.string().min(1).transform(Number),
23-
STATIC_OTP: z.enum(['1', '0']).transform(Number),
25+
STATIC_OTP: z.enum(['1', '0']).transform(Number).optional(),
2426
NODE_ENV: z.union([z.literal('production'), z.literal('development')]),
2527
SET_SESSION: z.string().transform((value) => !!Number(value)),
26-
GOOGLE_CLIENT_ID: z.string(),
27-
GOOGLE_CLIENT_SECRET: z.string(),
28-
GOOGLE_REDIRECT_URI: z.string(),
28+
GOOGLE_CLIENT_ID: z.string().optional(),
29+
GOOGLE_CLIENT_SECRET: z.string().optional(),
30+
GOOGLE_REDIRECT_URI: z.string().optional(),
2931
APP_NAME: z.string().default('API V1').optional(),
3032
APP_VERSION: z.string().default('1.0.0').optional(),
3133
});

src/openapi/magic-router.ts

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,38 @@ export type MaybePromise = void | Promise<void>;
3636
export type RequestAny = Request<IDontKnow, IDontKnow, IDontKnow, IDontKnow>;
3737
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3838
export type ResponseAny = Response<IDontKnow, Record<string, any>>;
39+
export type MagicPathType = `/${string}`;
40+
export type MagicRoutePType<PathSet extends boolean> = PathSet extends true
41+
? [reqAndRes: RequestAndResponseType, ...handlers: MagicMiddleware[]]
42+
: [
43+
path: MagicPathType,
44+
reqAndRes: RequestAndResponseType,
45+
...handlers: MagicMiddleware[],
46+
];
47+
export type MagicRouteRType<PathSet extends boolean> = Omit<
48+
MagicRouter<PathSet>,
49+
'route' | 'getRouter' | 'use'
50+
>;
51+
export type MagicMiddleware = (
52+
req: RequestAny,
53+
res: ResponseAny,
54+
next?: NextFunction,
55+
) => MaybePromise;
3956

4057
export type RequestAndResponseType = {
4158
requestType?: RequestZodSchemaType;
4259
responseModel?: ZodTypeAny;
4360
};
4461

45-
export class MagicRouter {
62+
export class MagicRouter<PathSet extends boolean = false> {
4663
private router: Router;
4764
private rootRoute: string;
65+
private currentPath?: MagicPathType;
4866

49-
constructor(rootRoute: string) {
67+
constructor(rootRoute: string, currentPath?: MagicPathType) {
5068
this.router = Router();
5169
this.rootRoute = rootRoute;
70+
this.currentPath = currentPath;
5271
}
5372

5473
private getPath(path: string) {
@@ -57,11 +76,9 @@ export class MagicRouter {
5776

5877
private wrapper(
5978
method: Method,
60-
path: string,
79+
path: MagicPathType,
6180
requestAndResponseType: RequestAndResponseType,
62-
...middlewares: Array<
63-
(req: RequestAny, res: ResponseAny, next?: NextFunction) => MaybePromise
64-
>
81+
...middlewares: Array<MagicMiddleware>
6582
): void {
6683
const bodyType = requestAndResponseType.requestType?.body;
6784
const paramsType = requestAndResponseType.requestType?.params;
@@ -185,59 +202,52 @@ export class MagicRouter {
185202
}
186203
}
187204

188-
public get(
189-
path: string,
190-
requestAndResponseType: RequestAndResponseType,
191-
...middlewares: Array<
192-
(req: RequestAny, res: ResponseAny, next?: NextFunction) => MaybePromise
193-
>
194-
): void {
195-
this.wrapper('get', path, requestAndResponseType, ...middlewares);
205+
public get(...args: MagicRoutePType<PathSet>): MagicRouteRType<PathSet> {
206+
return this.routeHandler('get', ...args);
196207
}
197208

198-
public post(
199-
path: string,
200-
requestAndResponseType: RequestAndResponseType,
201-
...middlewares: Array<
202-
(req: RequestAny, res: ResponseAny, next?: NextFunction) => MaybePromise
203-
>
204-
): void {
205-
this.wrapper('post', path, requestAndResponseType, ...middlewares);
209+
public post(...args: MagicRoutePType<PathSet>): MagicRouteRType<PathSet> {
210+
return this.routeHandler('post', ...args);
206211
}
207212

208-
public delete(
209-
path: string,
210-
requestAndResponseType: RequestAndResponseType,
211-
...middlewares: Array<
212-
(req: RequestAny, res: ResponseAny, next?: NextFunction) => MaybePromise
213-
>
214-
): void {
215-
this.wrapper('delete', path, requestAndResponseType, ...middlewares);
213+
public delete(...args: MagicRoutePType<PathSet>): MagicRouteRType<PathSet> {
214+
return this.routeHandler('delete', ...args);
216215
}
217216

218-
public patch(
219-
path: string,
220-
requestAndResponseType: RequestAndResponseType,
221-
...middlewares: Array<
222-
(req: RequestAny, res: ResponseAny, next?: NextFunction) => MaybePromise
223-
>
224-
): void {
225-
this.wrapper('patch', path, requestAndResponseType, ...middlewares);
217+
public patch(...args: MagicRoutePType<PathSet>): MagicRouteRType<PathSet> {
218+
return this.routeHandler('patch', ...args);
226219
}
227220

228-
public put(
229-
path: string,
230-
requestAndResponseType: RequestAndResponseType,
231-
...middlewares: Array<
232-
(req: RequestAny, res: ResponseAny, next?: NextFunction) => MaybePromise
233-
>
234-
): void {
235-
this.wrapper('put', path, requestAndResponseType, ...middlewares);
221+
public put(...args: MagicRoutePType<PathSet>): MagicRouteRType<PathSet> {
222+
return this.routeHandler('put', ...args);
236223
}
224+
237225
public use(...args: Parameters<Router['use']>): void {
238226
this.router.use(...args);
239227
}
240228

229+
public route(path: MagicPathType): MagicRouteRType<true> {
230+
return new MagicRouter<true>(this.rootRoute, path);
231+
}
232+
233+
private routeHandler(method: Method, ...args: MagicRoutePType<PathSet>) {
234+
if (this.currentPath) {
235+
const [reqAndRes, ...handlers] = args as [
236+
RequestAndResponseType,
237+
...MagicMiddleware[],
238+
];
239+
this.wrapper(method, this.currentPath, reqAndRes, ...handlers);
240+
} else {
241+
const [path, reqAndRes, ...handlers] = args as [
242+
MagicPathType,
243+
RequestAndResponseType,
244+
...MagicMiddleware[],
245+
];
246+
this.wrapper(method, path, reqAndRes, ...handlers);
247+
}
248+
return this;
249+
}
250+
241251
// Method to get the router instance
242252
public getRouter(): Router {
243253
return this.router;

0 commit comments

Comments
 (0)