Skip to content

Commit f91d95f

Browse files
committed
fixed sonar findigns
1 parent aa387ce commit f91d95f

File tree

2 files changed

+123
-140
lines changed

2 files changed

+123
-140
lines changed

packages/event-handler/src/http/Router.ts

Lines changed: 29 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ import {
7171
resolvePrefixedPath,
7272
} from './utils.js';
7373

74+
type MiddlewareOrHandler<
75+
TReqBody = never,
76+
TResBody extends HandlerResponse = HandlerResponse,
77+
> = Middleware[] | RouteHandler | TypedRouteHandler<TReqBody, TResBody>;
78+
79+
type HandlerOrOptions<
80+
TReqBody = never,
81+
TResBody extends HandlerResponse = HandlerResponse,
82+
> =
83+
| RouteHandler
84+
| TypedRouteHandler<TReqBody, TResBody>
85+
| { validation: ValidationConfig<TReqBody, TResBody> };
86+
7487
class Router {
7588
protected context: Record<string, unknown>;
7689

@@ -589,14 +602,8 @@ class Router {
589602
>(
590603
method: HttpMethod,
591604
path: Path,
592-
middlewareOrHandler?:
593-
| Middleware[]
594-
| RouteHandler
595-
| TypedRouteHandler<TReqBody, TResBody>,
596-
handlerOrOptions?:
597-
| RouteHandler
598-
| TypedRouteHandler<TReqBody, TResBody>
599-
| { validation: ValidationConfig<TReqBody, TResBody> },
605+
middlewareOrHandler?: MiddlewareOrHandler<TReqBody, TResBody>,
606+
handlerOrOptions?: HandlerOrOptions<TReqBody, TResBody>,
600607
options?: { validation: ValidationConfig<TReqBody, TResBody> }
601608
): MethodDecorator | undefined {
602609
// Case 1: method(path, [middleware], handler, { validation })
@@ -670,14 +677,8 @@ class Router {
670677
TResBody extends HandlerResponse = HandlerResponse,
671678
>(
672679
path: Path,
673-
middlewareOrHandler?:
674-
| Middleware[]
675-
| RouteHandler
676-
| TypedRouteHandler<TReqBody, TResBody>,
677-
handlerOrOptions?:
678-
| RouteHandler
679-
| TypedRouteHandler<TReqBody, TResBody>
680-
| { validation: ValidationConfig<TReqBody, TResBody> },
680+
middlewareOrHandler?: MiddlewareOrHandler<TReqBody, TResBody>,
681+
handlerOrOptions?: HandlerOrOptions<TReqBody, TResBody>,
681682
options?: { validation: ValidationConfig<TReqBody, TResBody> }
682683
): MethodDecorator | undefined {
683684
return this.#handleHttpMethod<TReqBody, TResBody>(
@@ -719,14 +720,8 @@ class Router {
719720
TResBody extends HandlerResponse = HandlerResponse,
720721
>(
721722
path: Path,
722-
middlewareOrHandler?:
723-
| Middleware[]
724-
| RouteHandler
725-
| TypedRouteHandler<TReqBody, TResBody>,
726-
handlerOrOptions?:
727-
| RouteHandler
728-
| TypedRouteHandler<TReqBody, TResBody>
729-
| { validation: ValidationConfig<TReqBody, TResBody> },
723+
middlewareOrHandler?: MiddlewareOrHandler<TReqBody, TResBody>,
724+
handlerOrOptions?: HandlerOrOptions<TReqBody, TResBody>,
730725
options?: { validation: ValidationConfig<TReqBody, TResBody> }
731726
): MethodDecorator | undefined {
732727
return this.#handleHttpMethod<TReqBody, TResBody>(
@@ -764,14 +759,8 @@ class Router {
764759
TResBody extends HandlerResponse = HandlerResponse,
765760
>(
766761
path: Path,
767-
middlewareOrHandler?:
768-
| Middleware[]
769-
| RouteHandler
770-
| TypedRouteHandler<TReqBody, TResBody>,
771-
handlerOrOptions?:
772-
| RouteHandler
773-
| TypedRouteHandler<TReqBody, TResBody>
774-
| { validation: ValidationConfig<TReqBody, TResBody> },
762+
middlewareOrHandler?: MiddlewareOrHandler<TReqBody, TResBody>,
763+
handlerOrOptions?: HandlerOrOptions<TReqBody, TResBody>,
775764
options?: { validation: ValidationConfig<TReqBody, TResBody> }
776765
): MethodDecorator | undefined {
777766
return this.#handleHttpMethod<TReqBody, TResBody>(
@@ -813,14 +802,8 @@ class Router {
813802
TResBody extends HandlerResponse = HandlerResponse,
814803
>(
815804
path: Path,
816-
middlewareOrHandler?:
817-
| Middleware[]
818-
| RouteHandler
819-
| TypedRouteHandler<TReqBody, TResBody>,
820-
handlerOrOptions?:
821-
| RouteHandler
822-
| TypedRouteHandler<TReqBody, TResBody>
823-
| { validation: ValidationConfig<TReqBody, TResBody> },
805+
middlewareOrHandler?: MiddlewareOrHandler<TReqBody, TResBody>,
806+
handlerOrOptions?: HandlerOrOptions<TReqBody, TResBody>,
824807
options?: { validation: ValidationConfig<TReqBody, TResBody> }
825808
): MethodDecorator | undefined {
826809
return this.#handleHttpMethod<TReqBody, TResBody>(
@@ -862,14 +845,8 @@ class Router {
862845
TResBody extends HandlerResponse = HandlerResponse,
863846
>(
864847
path: Path,
865-
middlewareOrHandler?:
866-
| Middleware[]
867-
| RouteHandler
868-
| TypedRouteHandler<TReqBody, TResBody>,
869-
handlerOrOptions?:
870-
| RouteHandler
871-
| TypedRouteHandler<TReqBody, TResBody>
872-
| { validation: ValidationConfig<TReqBody, TResBody> },
848+
middlewareOrHandler?: MiddlewareOrHandler<TReqBody, TResBody>,
849+
handlerOrOptions?: HandlerOrOptions<TReqBody, TResBody>,
873850
options?: { validation: ValidationConfig<TReqBody, TResBody> }
874851
): MethodDecorator | undefined {
875852
return this.#handleHttpMethod<TReqBody, TResBody>(
@@ -911,14 +888,8 @@ class Router {
911888
TResBody extends HandlerResponse = HandlerResponse,
912889
>(
913890
path: Path,
914-
middlewareOrHandler?:
915-
| Middleware[]
916-
| RouteHandler
917-
| TypedRouteHandler<TReqBody, TResBody>,
918-
handlerOrOptions?:
919-
| RouteHandler
920-
| TypedRouteHandler<TReqBody, TResBody>
921-
| { validation: ValidationConfig<TReqBody, TResBody> },
891+
middlewareOrHandler?: MiddlewareOrHandler<TReqBody, TResBody>,
892+
handlerOrOptions?: HandlerOrOptions<TReqBody, TResBody>,
922893
options?: { validation: ValidationConfig<TReqBody, TResBody> }
923894
): MethodDecorator | undefined {
924895
return this.#handleHttpMethod<TReqBody, TResBody>(
@@ -960,14 +931,8 @@ class Router {
960931
TResBody extends HandlerResponse = HandlerResponse,
961932
>(
962933
path: Path,
963-
middlewareOrHandler?:
964-
| Middleware[]
965-
| RouteHandler
966-
| TypedRouteHandler<TReqBody, TResBody>,
967-
handlerOrOptions?:
968-
| RouteHandler
969-
| TypedRouteHandler<TReqBody, TResBody>
970-
| { validation: ValidationConfig<TReqBody, TResBody> },
934+
middlewareOrHandler?: MiddlewareOrHandler<TReqBody, TResBody>,
935+
handlerOrOptions?: HandlerOrOptions<TReqBody, TResBody>,
971936
options?: { validation: ValidationConfig<TReqBody, TResBody> }
972937
): MethodDecorator | undefined {
973938
return this.#handleHttpMethod<TReqBody, TResBody>(

packages/event-handler/src/http/middleware/validation.ts

Lines changed: 94 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -31,92 +31,110 @@ export const createValidationMiddleware = <
3131
res: {} as ValidatedResponse<TResBody>,
3232
};
3333

34-
// Validate request
3534
if (reqSchemas) {
36-
if (reqSchemas.body) {
37-
const clonedRequest = reqCtx.req.clone();
38-
const contentType = reqCtx.req.headers.get('content-type');
39-
let bodyData: unknown;
40-
41-
if (contentType?.includes('application/json')) {
42-
try {
43-
bodyData = await clonedRequest.json();
44-
} catch {
45-
// If JSON parsing fails, get as text and let validator handle it
46-
bodyData = await reqCtx.req.clone().text();
47-
}
48-
} else {
49-
bodyData = await clonedRequest.text();
50-
}
51-
52-
const validatedBody = await validateRequest(
53-
reqSchemas.body,
54-
bodyData,
55-
'body'
56-
);
57-
(typedReqCtx.valid.req as ValidatedRequest<TReqBody>).body =
58-
validatedBody as TReqBody;
59-
}
60-
if (reqSchemas.headers) {
61-
const headers = Object.fromEntries(reqCtx.req.headers.entries());
62-
typedReqCtx.valid.req.headers = (await validateRequest(
63-
reqSchemas.headers,
64-
headers,
65-
'headers'
66-
)) as Record<string, string>;
67-
}
68-
if (reqSchemas.path) {
69-
typedReqCtx.valid.req.path = (await validateRequest(
70-
reqSchemas.path,
71-
reqCtx.params,
72-
'path'
73-
)) as Record<string, string>;
74-
}
75-
if (reqSchemas.query) {
76-
const query = Object.fromEntries(
77-
new URL(reqCtx.req.url).searchParams.entries()
78-
);
79-
typedReqCtx.valid.req.query = (await validateRequest(
80-
reqSchemas.query,
81-
query,
82-
'query'
83-
)) as Record<string, string>;
84-
}
35+
await validateRequestData(typedReqCtx, reqSchemas);
8536
}
8637

87-
// Execute handler
8838
await next();
8939

90-
// Validate response
9140
if (resSchemas) {
92-
const response = reqCtx.res;
93-
94-
if (resSchemas.body && response.body) {
95-
const clonedResponse = response.clone();
96-
const contentType = response.headers.get('content-type');
97-
const bodyData = contentType?.includes('application/json')
98-
? await clonedResponse.json()
99-
: await clonedResponse.text();
100-
101-
typedReqCtx.valid.res.body = (await validateResponse(
102-
resSchemas.body,
103-
bodyData,
104-
'body'
105-
)) as TResBody;
106-
}
107-
108-
if (resSchemas.headers) {
109-
const headers = Object.fromEntries(response.headers.entries());
110-
typedReqCtx.valid.res.headers = (await validateResponse(
111-
resSchemas.headers,
112-
headers,
113-
'headers'
114-
)) as Record<string, string>;
115-
}
41+
await validateResponseData(typedReqCtx, resSchemas);
11642
}
11743
};
11844
};
11945

46+
async function validateRequestData<TReqBody>(
47+
typedReqCtx: TypedRequestContext<TReqBody, HandlerResponse>,
48+
reqSchemas: NonNullable<ValidationConfig<TReqBody, HandlerResponse>['req']>
49+
): Promise<void> {
50+
if (reqSchemas.body) {
51+
const bodyData = await extractRequestBody(typedReqCtx.req);
52+
const validatedBody = await validateRequest(
53+
reqSchemas.body,
54+
bodyData,
55+
'body'
56+
);
57+
typedReqCtx.valid.req.body = validatedBody as TReqBody;
58+
}
59+
60+
if (reqSchemas.headers) {
61+
const headers = Object.fromEntries(typedReqCtx.req.headers.entries());
62+
typedReqCtx.valid.req.headers = (await validateRequest(
63+
reqSchemas.headers,
64+
headers,
65+
'headers'
66+
)) as Record<string, string>;
67+
}
68+
69+
if (reqSchemas.path) {
70+
typedReqCtx.valid.req.path = (await validateRequest(
71+
reqSchemas.path,
72+
typedReqCtx.params,
73+
'path'
74+
)) as Record<string, string>;
75+
}
76+
77+
if (reqSchemas.query) {
78+
const query = Object.fromEntries(
79+
new URL(typedReqCtx.req.url).searchParams.entries()
80+
);
81+
typedReqCtx.valid.req.query = (await validateRequest(
82+
reqSchemas.query,
83+
query,
84+
'query'
85+
)) as Record<string, string>;
86+
}
87+
}
88+
89+
async function validateResponseData<TResBody extends HandlerResponse>(
90+
typedReqCtx: TypedRequestContext<unknown, TResBody>,
91+
resSchemas: NonNullable<ValidationConfig<unknown, TResBody>['res']>
92+
): Promise<void> {
93+
const response = typedReqCtx.res;
94+
95+
if (resSchemas.body && response.body) {
96+
const bodyData = await extractResponseBody(response);
97+
typedReqCtx.valid.res.body = (await validateResponse(
98+
resSchemas.body,
99+
bodyData,
100+
'body'
101+
)) as TResBody;
102+
}
103+
104+
if (resSchemas.headers) {
105+
const headers = Object.fromEntries(response.headers.entries());
106+
typedReqCtx.valid.res.headers = (await validateResponse(
107+
resSchemas.headers,
108+
headers,
109+
'headers'
110+
)) as Record<string, string>;
111+
}
112+
}
113+
114+
async function extractRequestBody(req: Request): Promise<unknown> {
115+
const clonedRequest = req.clone();
116+
const contentType = req.headers.get('content-type');
117+
118+
if (contentType?.includes('application/json')) {
119+
try {
120+
return await clonedRequest.json();
121+
} catch {
122+
return await req.clone().text();
123+
}
124+
}
125+
126+
return await clonedRequest.text();
127+
}
128+
129+
async function extractResponseBody(response: Response): Promise<unknown> {
130+
const clonedResponse = response.clone();
131+
const contentType = response.headers.get('content-type');
132+
133+
return contentType?.includes('application/json')
134+
? await clonedResponse.json()
135+
: await clonedResponse.text();
136+
}
137+
120138
async function validateRequest(
121139
schema: StandardSchemaV1,
122140
data: unknown,

0 commit comments

Comments
 (0)