From a0e2c8d6803d6e8c307e4f7015b2e490f53e0be8 Mon Sep 17 00:00:00 2001 From: Florian Rudisch Date: Sat, 15 Jan 2022 20:10:20 +0100 Subject: [PATCH] Adding joi validation for other content than the request body like query parameter or something else in the request or context (#4) --- README.md | 12 +++++++++++- src/validation.test.ts | 7 ++++--- src/validation.ts | 40 ++++++++++++++++++++++------------------ 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 535a6ab..1371df0 100644 --- a/README.md +++ b/README.md @@ -62,13 +62,23 @@ The body of the response could be customized by adding a transformer like in the ```typescript export default middleware(handler, [ - validation(accountWithConnectionRequestSchema(), (message) => ({ + validation(schema, (message) => ({ type: 'Invalid request object', detail: message, })), ]) ``` +By default the request body is getting validated. To validate other parts of the request or context the `extractValidationContentFromRequest` function could be used, when initializing the middleware. + +```typescript +export default middleware(handler, [ + validation(schema, undefined, (req, context) => req.query.name)), +]) +``` + +In this example the `name` contained in the query is getting validated against the passed request. + ### Authorization To authorize a request the middleware function `authorization` could be used. The function is verifying a request parameter against a JWT Bearer Token. The information get extracted using two functions for the correct parameter and token counterpart. diff --git a/src/validation.test.ts b/src/validation.test.ts index 3ed6838..f8c8f9d 100644 --- a/src/validation.test.ts +++ b/src/validation.test.ts @@ -27,13 +27,14 @@ describe('The joi validator should', () => { expect(result).toBeUndefined(); }); - test('not call the validation when the method is GET', async () => { + test('successfully validate the object extracted through the passed function', async () => { requestMock.method = 'GET'; const schemaMock = mock(); + schemaMock.validate.mockReturnValue({ error: undefined, value: 'Test Validation' }); - const result = await sut(schemaMock)(contextMock, requestMock); + const result = await sut(schemaMock, undefined, () => 'test-extracted-content')(contextMock, requestMock); - expect(schemaMock.validate).not.toBeCalled(); + expect(schemaMock.validate).toBeCalledWith('test-extracted-content'); expect(result).toBeUndefined(); }); diff --git a/src/validation.ts b/src/validation.ts index 860a3a4..cb7d593 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -3,25 +3,29 @@ import { ObjectSchema } from 'joi'; import { ApplicationError } from './applicationError'; import { MiddlewareFunction } from './middleware'; -export default (schema: ObjectSchema, transformErrorMessage?: (message: string) => unknown): MiddlewareFunction => { +export default ( + schema: ObjectSchema, + transformErrorMessage?: (message: string) => unknown, + extractValidationContentFromRequest?: (context: Context, req: HttpRequest) => unknown, +): MiddlewareFunction => { return (context: Context, req: HttpRequest): Promise => { - const body = req.body; - if (req.method !== 'GET') { - const validationResult = schema.validate(body); - if (validationResult && validationResult.error) { - context.log.verbose(validationResult); - return Promise.reject( - new ApplicationError( - 'Validation Error', - 400, - transformErrorMessage - ? transformErrorMessage(validationResult.error.message) - : { - message: validationResult.error.message, - }, - ), - ); - } + const toBeValidatedContent = extractValidationContentFromRequest + ? extractValidationContentFromRequest(context, req) + : req.body; + const validationResult = schema.validate(toBeValidatedContent); + if (validationResult && validationResult.error) { + context.log.verbose(validationResult); + return Promise.reject( + new ApplicationError( + 'Validation Error', + 400, + transformErrorMessage + ? transformErrorMessage(validationResult.error.message) + : { + message: validationResult.error.message, + }, + ), + ); } return Promise.resolve(); };