Skip to content

Commit

Permalink
feat: keep original headers after validation
Browse files Browse the repository at this point in the history
  • Loading branch information
mrnagydavid committed Oct 22, 2024
1 parent ac1e459 commit 74e6c38
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 4 deletions.
56 changes: 54 additions & 2 deletions src/server/validation/validateRequest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ describe('validateRequest.headers', () => {
})

expect(response).toMatchObject({ ok: 1 })
expect(response.headers).toEqual({
expect(response.headers).toMatchObject({
shortstring: 'shortstring',
numeric: 123,
numeric: '123',
bool: '1',
sessionid: 'sessionid',
})
Expand Down Expand Up @@ -154,4 +154,56 @@ describe('validateRequest.headers', () => {
expect(err.cause.message).toContain('"REDACTED": "REDACTED"')
expect(err.cause.message).not.toContain('sessionid')
})

test('should not replace the headers with the validated value by default', async () => {
const response = await app.get<TestResponse>('', {
headers: {
shortstring: 'shortstring',
numeric: '123',
bool: '1',
sessionid: 'sessionid',
foo: 'bar',
},
})

expect(response.headers).toMatchObject({
shortstring: 'shortstring',
numeric: '123',
bool: '1',
sessionid: 'sessionid',
foo: 'bar',
})
})

test('should replace the headers with the validated value when configured so', async () => {
const resource = getDefaultRouter().get('/', async (req, res) => {
validateRequest.headers(
req,
objectSchema<any>({
shortstring: stringSchema.min(8).max(16),
numeric: numberSchema,
}),
{ keepOriginal: false },
)

res.json({ ok: 1, headers: req.headers })
})
const app = expressTestService.createAppFromResource(resource)

const response = await app.get<TestResponse>('', {
headers: {
shortstring: 'shortstring',
numeric: 123,
foo: 'bar',
},
})

expect(response.headers).toEqual({
shortstring: 'shortstring',
numeric: 123, // converted to number
// foo: 'bar' // fields not in the schema are removed
})

await app.close()
})
})
25 changes: 23 additions & 2 deletions src/server/validation/validateRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export interface ReqValidationOptions<ERR extends Error> {
* If true - `genericErrorHandler` will report it to errorReporter (aka Sentry).
*/
report?: boolean | ((err: ERR) => boolean)

/**
* When set to true, the validated object will not be replaced with the Joi-converted value.
*/
keepOriginal?: boolean
}

/**
Expand Down Expand Up @@ -55,12 +60,25 @@ class ValidateRequest {
return this.validate(req, 'params', schema, opt)
}

/**
* Validates `req.headers` against the provided Joi schema.
*
* Note: as opposed to other methods, this method does not mutate `req.headers` in case of success,
* i.e. schemas that cast values will not have any effect.
*
* If you wish to mutate `req.headers` with the validated value, use `keepOriginal: false` option.
* Keep in mind that this will also remove all values that are not in the schema.
*/
headers<T>(
req: BackendRequest,
schema: AnySchema<T>,
opt: ReqValidationOptions<JoiValidationError> = {},
): T {
return this.validate(req, 'headers', schema, opt)
const options: ReqValidationOptions<JoiValidationError> = {
keepOriginal: true,
...opt,
}
return this.validate(req, 'headers', schema, options)
}

private validate<T>(
Expand Down Expand Up @@ -92,7 +110,10 @@ class ValidateRequest {
}

// mutate req to replace the property with the value, converted by Joi
req[reqProperty] = value
if (!opt.keepOriginal) {
req[reqProperty] = value
}

return value
}
}
Expand Down

0 comments on commit 74e6c38

Please sign in to comment.