Skip to content

Commit

Permalink
fix: separate validation handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
solufa committed Jun 13, 2020
1 parent 081bde7 commit 5503330
Showing 1 changed file with 46 additions and 36 deletions.
82 changes: 46 additions & 36 deletions packages/frourio/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,45 +141,57 @@ export type ControllerTree = {
}
}

const methodsToHandler = (
validator: Validators | undefined,
methodCallback: ServerMethods<any, any>[LowerHttpMethod],
numberTypeParams: string[]
): RequestHandler => async (req, res) => {
let params: Record<string, string | number>
const createValidateHandler = (validator: Validators | undefined): RequestHandler => (
req,
res,
next
) =>
Promise.all([
validator?.query &&
(Object.keys(req.query).length || validator.query.required ? true : undefined) &&
validateOrReject(Object.assign(new validator.query.Class(), req.query)),
validator?.headers &&
(Object.keys(req.headers).length || validator.headers.required ? true : undefined) &&
validateOrReject(Object.assign(new validator.headers.Class(), req.headers)),
validator?.body &&
(Object.keys(req.body).length || validator.body.required ? true : undefined) &&
validateOrReject(Object.assign(new validator.body.Class(), req.body))
])
.then(() => next())
.catch(() => res.sendStatus(400))

const createTypedParamsHandler = (numberTypeParams: string[]): RequestHandler => async (
req,
res,
next
) => {
const typedParams: Record<string, string | number> = { ...req.params }

try {
params = numberTypeParams.reduce<typeof params>((p, c) => {
const val = Number(p[c])
if (isNaN(val)) throw new Error()

return { ...p, [c]: val }
}, req.params)

await Promise.all([
validator?.query &&
(Object.keys(req.query).length || validator.query.required ? true : undefined) &&
validateOrReject(Object.assign(new validator.query.Class(), req.query)),
validator?.headers &&
(Object.keys(req.headers).length || validator.headers.required ? true : undefined) &&
validateOrReject(Object.assign(new validator.headers.Class(), req.headers)),
validator?.body &&
(Object.keys(req.body).length || validator.body.required ? true : undefined) &&
validateOrReject(Object.assign(new validator.body.Class(), req.body))
])
} catch (e) {
res.sendStatus(400)
return
for (const key in numberTypeParams) {
const val = Number(typedParams[key])
if (isNaN(val)) {
res.sendStatus(400)
return
}

typedParams[key] = val
}

;(req as any).typedParams = typedParams
next()
}

const methodsToHandler = (
methodCallback: ServerMethods<any, any>[LowerHttpMethod]
): RequestHandler => async (req, res) => {
try {
const result = methodCallback({
query: req.query,
path: req.path,
method: req.method as HttpMethod,
body: req.body,
headers: req.headers,
params,
params: (req as any).typedParams,
user: (req as any).user,
files: req.files
})
Expand Down Expand Up @@ -210,23 +222,21 @@ export const createRouter = (
}

if (ctrl.controller) {
const typedParamsHandler = createTypedParamsHandler(numberTypeParams)
const ctrlMiddlewareList = Array.isArray(ctrl.ctrlMiddleware)
? ctrl.ctrlMiddleware
: ctrl.ctrlMiddleware
? [ctrl.ctrlMiddleware]
: []

for (const method in ctrl.controller) {
const handler = methodsToHandler(
ctrl.validator?.[method as LowerHttpMethod],
ctrl.controller[method],
numberTypeParams
)
const validateHandler = createValidateHandler(ctrl.validator?.[method as LowerHttpMethod])
const handler = methodsToHandler(ctrl.controller[method])

;(router.route('/') as any)[method](
ctrl.uploader?.includes(method)
? [uploader, ...ctrlMiddlewareList, handler]
: [...ctrlMiddlewareList, handler]
? [uploader, validateHandler, typedParamsHandler, ...ctrlMiddlewareList, handler]
: [validateHandler, typedParamsHandler, ...ctrlMiddlewareList, handler]
)
}
}
Expand Down

0 comments on commit 5503330

Please sign in to comment.