Skip to content

Commit

Permalink
feat: remove obsolete reqValidation in favour of validateRequest
Browse files Browse the repository at this point in the history
  • Loading branch information
kirillgroshkov committed Mar 6, 2024
1 parent b5e356e commit 6b48182
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 748 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"yargs": "^17.0.0"
},
"devDependencies": {
"@naturalcycles/bench-lib": "^1.0.7",
"@naturalcycles/bench-lib": "^2.0.0",
"@naturalcycles/dev-lib": "^13.0.0",
"@sentry/node": "^7.0.0",
"@types/ejs": "^3.0.0",
Expand Down
20 changes: 9 additions & 11 deletions scripts/validation.bench.script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ import { runCannon } from '@naturalcycles/bench-lib'
import { jsonSchema } from '@naturalcycles/js-lib'
import { objectSchema, stringSchema, runScript } from '@naturalcycles/nodejs-lib'
import express = require('express')
import { BackendApplication, reqValidation, validateBody } from '../src'
import { BackendApplication, validateBody, validateRequest } from '../src'

interface PwInput {
pw: string
}

const pwInputSchema = objectSchema<PwInput>({
pw: stringSchema.min(6),
})

function createApp(): BackendApplication {
const app = express()
app.disable('etag')
Expand Down Expand Up @@ -46,16 +50,10 @@ runScript(async () => {
},
'03-joi': async () => {
const app = createApp()
app.post(
'/',
reqValidation(
'body',
objectSchema<PwInput>({
pw: stringSchema.min(6),
}),
),
(req, res) => res.json({ hello: 'world' }),
)
app.post('/', (req, res) => {
const _input = validateRequest.body(req, pwInputSchema)
res.json({ hello: 'world' })
})
return http.createServer(app)
},
},
Expand Down
22 changes: 11 additions & 11 deletions src/db/httpDBRequestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '@naturalcycles/db-lib/dist/validation'
import { ObjectWithId } from '@naturalcycles/js-lib'
import { anyObjectSchema, arraySchema, objectSchema, stringSchema } from '@naturalcycles/nodejs-lib'
import { BackendRouter, getDefaultRouter, reqValidation } from '..'
import { BackendRouter, getDefaultRouter, validateRequest } from '..'

export interface GetByIdsInput {
table: string
Expand Down Expand Up @@ -84,28 +84,28 @@ export function httpDBRequestHandler(db: CommonDB): BackendRouter {
// })

// getByIds
router.put('/getByIds', reqValidation('body', getByIdsInputSchema), async (req, res) => {
const { table, ids, opt } = req.body as GetByIdsInput
router.put('/getByIds', async (req, res) => {
const { table, ids, opt } = validateRequest.body(req, getByIdsInputSchema)
res.json(await db.getByIds(table, ids, opt))
})

// runQuery
router.put('/runQuery', reqValidation('body', runQueryInputSchema), async (req, res) => {
const { query, opt } = req.body as RunQueryInput
router.put('/runQuery', async (req, res) => {
const { query, opt } = validateRequest.body(req, runQueryInputSchema)
const q = DBQuery.fromPlainObject(query)
res.json(await db.runQuery(q, opt))
})

// runQueryCount
router.put('/runQueryCount', reqValidation('body', runQueryInputSchema), async (req, res) => {
const { query, opt } = req.body as RunQueryInput
router.put('/runQueryCount', async (req, res) => {
const { query, opt } = validateRequest.body(req, runQueryInputSchema)
const q = DBQuery.fromPlainObject(query)
res.json(await db.runQueryCount(q, opt))
})

// saveBatch
router.put('/saveBatch', reqValidation('body', saveBatchInputSchema), async (req, res) => {
const { table, rows, opt } = req.body as SaveBatchInput
router.put('/saveBatch', async (req, res) => {
const { table, rows, opt } = validateRequest.body(req, saveBatchInputSchema)
await db.saveBatch(table, rows, opt)
res.end()
})
Expand All @@ -117,8 +117,8 @@ export function httpDBRequestHandler(db: CommonDB): BackendRouter {
// })

// deleteByQuery
router.put('/deleteByQuery', reqValidation('body', runQueryInputSchema), async (req, res) => {
const { query, opt } = req.body as RunQueryInput
router.put('/deleteByQuery', async (req, res) => {
const { query, opt } = validateRequest.body(req, runQueryInputSchema)
const q = DBQuery.fromPlainObject(query)
res.json(await db.deleteByQuery(q, opt))
})
Expand Down
18 changes: 8 additions & 10 deletions src/general.server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { arraySchema, deflateString, objectSchema } from '@naturalcycles/nodejs-lib'
import { safeJsonMiddleware } from './server/safeJsonMiddleware'
import { expressTestService } from './testing'
import { getDefaultRouter, reqValidation } from './index'
import { getDefaultRouter, validateRequest } from './index'

const router = getDefaultRouter()
router.get('/circular', safeJsonMiddleware(), async req => {
Expand All @@ -21,18 +21,16 @@ router.get('/circular', safeJsonMiddleware(), async req => {
})
})

router.post(
'/compressedBody',
reqValidation(
'body',
router.post('/compressedBody', async (req, res) => {
const body = validateRequest.body(
req,
objectSchema({
items: arraySchema(),
}),
),
async (req, res) => {
res.json(req.body)
},
)
)

res.json(body)
})

const app = expressTestService.createAppFromResource(router)
afterAll(async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export * from './server/notFoundMiddleware'
export * from './server/okMiddleware'
export * from './server/basicAuthMiddleware'
export * from './server/requestTimeoutMiddleware'
export * from './server/validation/reqValidationMiddleware'
export * from './server/validation/validateRequest'
export * from './server/simpleRequestLoggerMiddleware'
export * from './server/serverStatusMiddleware'
export * from './server/validation/validateMiddleware'
Expand Down
2 changes: 1 addition & 1 deletion src/server/validation/validateMiddleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ afterAll(async () => {

test('validateBody', async () => {
// should pass (no error)
await app.put('changePassword', {
await app.put('changePassword2', {
json: {
pw: 'longEnough',
},
Expand Down
2 changes: 1 addition & 1 deletion src/server/validation/validateMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { JsonSchema, JsonSchemaBuilder, _get, AppError } from '@naturalcycles/js-lib'
import { AjvSchema, AjvValidationError } from '@naturalcycles/nodejs-lib'
import { BackendRequestHandler } from '../server.model'
import { ReqValidationOptions } from './reqValidationMiddleware'
import { ReqValidationOptions } from './validateRequest'

const REDACTED = 'REDACTED'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,6 @@ afterAll(async () => {
await app.close()
})

test('reqValidation', async () => {
// should pass (no error)
await app.put('changePassword', {
json: {
pw: 'longEnough',
},
})

const pw = 'short'
const err = await app.expectError({
url: 'changePassword',
method: 'PUT',
json: {
pw,
},
})
expect(err.data.responseStatusCode).toBe(400)
expect(err.cause.message).not.toContain(pw)
expect(err.cause.message).toContain('REDACTED')
expect(err.cause).toMatchInlineSnapshot(`
{
"data": {
"backendResponseStatusCode": 400,
"httpStatusCode": 400,
"joiValidationErrorItems": [],
"joiValidationObjectName": "request body",
},
"message": "Invalid request body
{
"pw" [1]: "REDACTED"
}
[1] "pw" length must be at least 8 characters long",
"name": "AppError",
}
`)

expect(_inspect(err.cause)).toMatchInlineSnapshot(`
"AppError: Invalid request body
{
"pw" [1]: "REDACTED"
}
[1] "pw" length must be at least 8 characters long"
`)
})

test('validateRequest', async () => {
// should pass (no error)
await app.put('changePasswordFn', {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { _get, AppError } from '@naturalcycles/js-lib'
import { AnySchema, getValidationResult, JoiValidationError } from '@naturalcycles/nodejs-lib'
import { BackendRequest, BackendRequestHandler } from '../server.model'
import { BackendRequest } from '../server.model'

const REDACTED = 'REDACTED'

Expand All @@ -18,40 +18,6 @@ export interface ReqValidationOptions<ERR extends Error> {
report?: boolean | ((err: ERR) => boolean)
}

export function reqValidation(
reqProperty: 'body' | 'params' | 'query',
schema: AnySchema,
opt: ReqValidationOptions<JoiValidationError> = {},
): BackendRequestHandler {
const reportPredicate =
typeof opt.report === 'function' ? opt.report : () => opt.report as boolean | undefined

return (req, res, next) => {
const { value, error } = getValidationResult(req[reqProperty], schema, `request ${reqProperty}`)
if (error) {
const report = reportPredicate(error)

if (opt.redactPaths) {
redact(opt.redactPaths, req[reqProperty], error)
error.data.joiValidationErrorItems.length = 0 // clears the array
delete error.data.annotation
}

return next(
new AppError(error.message, {
backendResponseStatusCode: 400,
report,
...error.data,
}),
)
}

// mutate req to replace the property with the value, converted by Joi
req[reqProperty] = value
next()
}
}

/**
* Mutates error
*/
Expand Down
2 changes: 1 addition & 1 deletion src/server/validation/zodValidateMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { _get, AppError, ZodSchema, ZodValidationError, zSafeValidate } from '@naturalcycles/js-lib'
import { BackendRequestHandler } from '../server.model'
import { ReqValidationOptions } from './reqValidationMiddleware'
import { ReqValidationOptions } from './validateRequest'

const REDACTED = 'REDACTED'

Expand Down
16 changes: 1 addition & 15 deletions src/test/debug.resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AppError, jsonSchema } from '@naturalcycles/js-lib'
import { objectSchema, stringSchema } from '@naturalcycles/nodejs-lib'
import { getDefaultRouter, reqValidation, validateRequest } from '..'
import { getDefaultRouter, validateRequest } from '..'
import { validateBody } from '../server/validation/validateMiddleware'

const router = getDefaultRouter()
Expand All @@ -14,20 +14,6 @@ interface PwInput {
pw: string
}

router.put(
'/changePassword',
reqValidation(
'body',
objectSchema<PwInput>({
pw: stringSchema.min(8),
}),
{ redactPaths: ['pw'] },
),
async (_req, res) => {
res.json({ ok: 1 })
},
)

router.put('/changePasswordFn', async (req, res) => {
const _input = validateRequest.body(
req,
Expand Down
Loading

0 comments on commit 6b48182

Please sign in to comment.