diff --git a/.changeset/proud-beans-flow.md b/.changeset/proud-beans-flow.md new file mode 100644 index 0000000..73eb9f0 --- /dev/null +++ b/.changeset/proud-beans-flow.md @@ -0,0 +1,5 @@ +--- +"schemeit": minor +--- + +added options and updated readme diff --git a/README.md b/README.md index 2c0e4e9..75ffd20 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,48 @@ # SchemeIt A lightweight express-js request validator, originally written for my personal projects and separated out into its own package for easier use. +Schemeit will check individual elements against their chosen validators, ensure all non-optional elements are present in a payload and can also optionally enforce `noExtraElements` to prevent bloated payloads. ## Install ``` npm install schemeit ``` + +## Usage + +The following is a basic example usage of schemeit to build a validator middleware for an endpoint: + +``` +import express from "express"; +import { NumberValidator, StringValidator, validator } from '../Schemic'; + +const app = express(); + +const testValidator = validator({ + name: StringValidator(), + age: NumberValidator.optional() +}); + +app.post('/test', testValidator, async (request: Request, response: Response) => { + response.status(200).json({ message: 'Success!' }); +}); + +app.listen(3000); + +``` + +You can also use the exported function `createValidator` to create your own validation function with custom rules like so: + +``` +const SpecificStringValidator: ValidationFunction = createValidator((object: unknown) => { + return object === 'foo' || object === 'bar'; +}); +``` + +## Validator Options + +| Option | Description | +| --------------- | ---------------------------------------------------------------------------------------------------- | +| noExtraElements | Rejects payloads with elements that do not exist in the validator schema | +| errorListName | Sets the name of the error list returned by the validator middleware, by default it is just `errors` | diff --git a/src/@types/index.ts b/src/@types/index.ts index 6d14452..e9a8dc6 100644 --- a/src/@types/index.ts +++ b/src/@types/index.ts @@ -3,6 +3,11 @@ export type DataTypeValidator = { optional?: boolean; }; +export type ValidatorOptions = { + noExtraElements?: boolean; + errorListName?: string; +}; + export type ValidationFunction = (() => DataTypeValidator) & { optional: () => DataTypeValidator }; export type ValidationError = Record; export type Payload = Record | null; diff --git a/src/index.ts b/src/index.ts index 5fb8e1c..aec7f8a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,11 @@ import { Request, Response, NextFunction, RequestHandler } from 'express'; -import { DataTypeValidator, ValidationError, Payload, ValidationFunction } from './@types/index'; +import { + DataTypeValidator, + ValidationError, + Payload, + ValidationFunction, + ValidatorOptions +} from './@types/index'; const extractPayload = (request: Request): Payload => { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument @@ -46,7 +52,10 @@ export const BooleanValidator = createValidator((object) => typeof object === 'b * @param validators The validation rules to follow * @returns {RequestHandler} An express middleware */ -export const validator = (validators: Record): RequestHandler => { +export const validator = ( + validators: Record, + options?: ValidatorOptions +): RequestHandler => { return (request: Request, response: Response, next: NextFunction) => { const errors: ValidationError = {}; const payload: Payload = extractPayload(request); @@ -60,12 +69,21 @@ export const validator = (validators: Record): Reques errors[key] = 'Required element is missing or undefined'; } } else if (!validator.validate(value)) { - errors[key] = 'Invalid type'; + errors[key] = 'Invalid type: expected'; + } + } + + if (options?.noExtraElements) { + for (const key in payload) { + if (!validators[key]) { + errors[key] = 'Element does not exist in validator'; + } } } if (Object.keys(errors).length) { - return response.status(400).json({ errors }); + const errorResponseKey = options?.errorListName ? options.errorListName : 'errors'; + return response.status(400).json({ [errorResponseKey]: errors }); } next();