Validate Any

Validate Any is a type validator mainly for Typescript (also works with Javascript) available here. Ever faced those issues where you're trying to make sure a type any is an instance of an interface? This is the issue this package was designed to solve. With this package, you can safely assert the type for an object and return customised errors if the types are incorrect.
Motivation
I hate it when I am unable to validate the request types of JSON objects in Express requests. I wanted to be able to reject a request before my request handlers used the request body. I also didn't like casting the type of the body in the request.
Features
validate function to validate the data type of a variable
- Validate Any can read the function types of
- Strings
- Numbers
- Booleans
- Undefined
- Null
- Lists
- Objects
- Classes
- Validate Any is built to automatically return you the typescript annotations generated by the schema you pass, in the
data property
- Detailed error messages to tell you where any validation errors occured
- API Middleware to simplify its usage with Express or NextJS
Installation
With yarn
$ npm install validate-any
With npm
$ yarn add validate-any
Usage
Import the module like this:
import { validate } from "validate-any"
const { validate } = require("validate-any")
How the validate function works
The validate function is the main validator in this package.
It is a function which can take 2 (3: optional) parameters.
validate parameters:
1 | any | The object we are checking |
2 | Validator | A specific rule to compare the object to (more about this later) |
3 | string? | The name of the root object when logs display errors. Defaults to * as root |
The type Validator is something you don't need to worry about. Just know that it is the Typescript type for a rule.
Rules can look like STRING() or NUMBER().
validate returns an object containing:
| success | boolean | Whether the validation of the object was a success or failure. true if success, false if failure |
| errors | iValidationError[] | The list of corrections to make if any |
| data | T | The data you passed in with type annotations from the schema you passed in |
iValidationError is the data type for an error
| location | string | Where in the object did an error occur. E.g. "* > settings > wallpaper" |
| message | string | Description of what the error is |
| expected | string | The expected type of value |
| value | T | The value given |
In the examples below, you will see in the error object I only show the error message and display a "..." after it.
This is because I don't want to display unnecessary information.
However, every single error will have all the properties defined here
Also do note that the location started with a *.
This is the name of the root defined here
Making a rule
There are infinite combinations of rules we can make. The complexity of the rule only depends on how much code you are
willing to write.
Validation basics with STRING()
Here is how to validate a string
console.log(validate("string", STRING()))
console.log(validate(0, STRING()))
The function STRING with nothing in the parameters represents a type string.
This method can also take in items in the parameters:
(empty) | validates if the input is a string |
RegExp | validates if the input is a string and matches the RegExp |
...string[] | validates if the input is a string and matches any of the given strings |
import { validate, STRING } from "validate-any"
console.log(validate("string", STRING()))
console.log(validate(0, STRING()))
console.log(validate("string", STRING(/^string$/)))
console.log(validate("string", STRING(/^something-else$/)))
console.log(validate("string", STRING("does", "the", "string", "match", "?")))
console.log(validate("string", STRING("doesn't", "match"), "my-string"))
Validating a number with NUMBER()
Because STRING() validates strings, it's obvious that NUMBER() validates numbers. NUMBER() works the same was as STRING() except allows a different set of parameters:
(empty) | validates if the input is a number |
...number[] | validates if the input is a number and matches any of the given numbers |
import { validate, NUMBER } from "validate-any"
console.log(validate(3, NUMBER()))
console.log(validate("string", NUMBER()))
console.log(validate(3, NUMBER(1, 2, 3, 4, 5)))
console.log(validate(3, NUMBER(6, 7, 8, 9, 10)))
Validating a boolean with BOOLEAN()
BOOLEAN() allows comparison of booleans only
(empty) | validates if the input is a boolean |
boolean | validates if the input is a boolean and if the booleans are equal |
import { validate, BOOLEAN } from "validate-any"
console.log(validate(true, BOOLEAN()))
console.log(validate("string", BOOLEAN()))
console.log(validate(true, BOOLEAN(true)))
console.log(validate(false, BOOLEAN(true)))
Validating null with NULL()
NULL() doesn't allow variations of the parameters
(empty) | validates if the input is a null |
import { validate, NULL } from "validate-any"
console.log(validate(null, NULL()))
console.log(validate(undefined, NULL()))
Validating undefined with UNDEFINED()
Just like NULL(), UNDEFINED() doesn't allow variations of the parameters
| (empty) | validates if the input is a undefined |
import { validate, UNDEFINED } from "validate-any"
console.log(validate(undefined, UNDEFINED()))
console.log(validate(null, UNDEFINED()))
Validating a list with LIST()
This one's a bit more complicated. LIST() allows a few sets of parameters:
(empty) | validates if the input is a list |
...Validator[] | validates if the input is a list and checks if all items in the list match at least 1 of the Rules stated |
import { validate, LIST, STRING, NUMBER } from "validate-any"
console.log(validate([1, 2, 3, 4, 5], LIST()))
console.log(validate({ property: "value" }, LIST()))
console.log(validate(["one", "two", "three"], LIST(STRING())))
console.log(validate([1, "two", 3], LIST(NUMBER())))
console.log(validate([1, "two", []], LIST(STRING(), NUMBER(), LIST())))
console.log(validate([1, "two", null], LIST(STRING(), NUMBER())))
const usernames = ["jack", "_jack", "-jack"]
console.log(validate(usernames, LIST(STRING(/^[a-zA-Z]/))))
const codes = [34, 76, 92]
console.log(validate(codes, LIST(NUMBER(34, 76, 92))))
This way, we can make checking of list types much more detailed
Validating an object with OBJECT()
We can use OBJECT() to validate objects.
OBJECT() only allows 1 optional parameter which maps out what the properties will look like
import { validate, OBJECT } from "validate-any"
console.log(validate({ property: "value" }, OBJECT()))
console.log(validate({ property: "value" }, OBJECT({})))
console.log(validate({ property: "value" }, OBJECT({ property: STRING() })))
console.log(
validate(
{
property: "value"
},
OBJECT({
prop: STRING()
})
)
)
console.log(
validate(
{
property: "value",
layer: {
deepProperty: ["", 0, null, undefined, false]
}
},
OBJECT({
property: STRING(),
layer: OBJECT({
deepProperty: LIST(
STRING(),
NUMBER(0),
NULL(),
UNDEFINED(),
BOOLEAN(false)
)
})
})
)
)
Validating the or operation with OR()
If you want either of a few rules to match, use the OR() operator. This function takes multiple parameters:
...Validator[] | A list of rules to test on the input |
import { validate, OR, STRING, NUMBER, BOOLEAN } from "validate-any"
console.log(validate("string", OR()))
console.log(validate("string", OR(STRING(), NUMBER())))
console.log(validate("string", OR(BOOLEAN(), NUMBER())))
Using withValidBody with Express or Next
You can also import the module as a middleware to be used with Express or Next.
This way, you can verify the types of the req.body before invalid types mess your code up
import { OBJECT, STRING, withValidBody } from "validate-any"
app.post(
"/body",
withValidBody(OBJECT({ usnm: STRING(), pswd: STRING() }))(
(req, res) => {
const { usnm, pswd } = req.body
console.log(`Username: ${usnm}`, `Password: ${pswd}`)
res.end()
}
)
)
export default withValidBody(OBJECT({ usnm: STRING(), pswd: STRING() }))(
(req, res) => {
const { usnm, pswd } = req.body
console.log(`Username: ${usnm}`, `Password: ${pswd}`)
res.end()
}
)
The withValidBody takes in 2 parameters:
1 | Validator | Rule to compare the req.body with |
2 | handler | Handler to handle the request if it works |
Because of the middleware, in Typescript you can now safely use type assertions.
Also, now for both Typescript and Javascript, you can safely use the variables like
they are the defined types and not have to worry about invalid types crashing your server!
Using withValidQuery with Express or Next
The withValidQuery works the same way as withValidBody but it validates the req.query instead.
Testing
Validate Any's individual validators are tested with Jest. To run the tests, run the command
$ npm run test
Built with
- TypeScript
- Jest
- Miscellaneous