Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pujitm/fun-ov
Flexible functional object validation for API's & highly customized software
https://github.com/pujitm/fun-ov
functional-programming javascript typescript validation
Last synced: 13 days ago
JSON representation
Flexible functional object validation for API's & highly customized software
- Host: GitHub
- URL: https://github.com/pujitm/fun-ov
- Owner: pujitm
- License: mit
- Created: 2022-02-14T22:18:55.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2022-09-06T03:53:17.000Z (over 2 years ago)
- Last Synced: 2025-01-18T07:16:23.318Z (16 days ago)
- Topics: functional-programming, javascript, typescript, validation
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/fun-ov
- Size: 267 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
- License: LICENSE
Awesome Lists containing this project
README
# Functional Object Validation for Typescript and Javascipt
Fun-ov makes runtime validation easy, flexible, and maintainable at scale (I hope). It's great for API's, games, and business logic.
## Getting Started
```bash
npm install fun-ov
# Or
yarn add fun-ov
``````ts
import { makeObjectChecker, makeListChecker, resultIsError } from "fun-ov";
// Or
import * as Fun from "fun-ov";// You're ready to make or adapt your validators. Example:
import { is, or, resultIsError } from "fun-ov";type Action = 'like' | 'comment' | 'subscribe';
const checkAction = or(is('like'), is('comment'), is('subscribe'));// Get a value from somewhere else, like an HTTP request. This time, it's 'dislike'
const result = checkAction("dislike");
if (resultIsError(result)) {
console.log("Don't @ me - YT. Fix one of these:", result);
}// Technically, you could use a go-like pattern, but sometimes, false might mean an error.
const err = checkAction("dislike");
if (err) console.log("yell");
if (checkAction("sleep")) console.log("sleep is good, but not here :(");
```## Usage
A validator (also called 'checker') is a function that returns any errors with the input value. No errors, no return value.
This behavior is defined in `lib/rules.ts` via the `resultIsError` function.
Once you know there's an error, you can log it, display it to an end-user, or fix it, but that gets unwieldy pretty quick, especially if rules can change on the fly.
Composing these kinds of functions makes complex logic ([like the Stripe Connect API](https://stripe.com/docs/api/external_account_bank_accounts/create)) accessible and readable without much boilerplate.
Example:
```ts
// From test/company.ts
export const validateBankAccount = makeObjectChecker({
routing_number: isNonEmptyString, // Can replace these with any combined validation function
account_number: isNonEmptyString, // See the Validation type in lib/rules.ts
account_holder_name: isNonEmptyString,
account_holder_type: is("company"),
});export const validateCompany = makeObjectChecker({
name: validateNames, // another object validator made using `makeObjectChecker`
bank_account: optional(validateBankAccount),
website: optional(checkIfString),
tax_id: optional(checkIfString),
email: optional(checkIfString),
tos_accepted: and(checkIfBoolean, (accepted, company: Company) => {
if (company.bank_account && !accepted)
return "must accept TOS to maintain bank account";
}),
});
// Validation errors will retain shape of object, so you know what properties were erroneous
```This package provides building blocks to help you build your own validation.
### Helpers
These functions return a Validator. You can run those validators with input, or you can combine them with other validators to make a bigger, overarching validator.
The format will be `function_name: Function input. What the returned validator will check, and how it will behave`.
Remember, Validators will only return if there is an error.
#### Identity & Equality
*See lib/equal.ts*
`is`: Takes one input. Validator checks if final input is equal (===) to that.
#### Logical Operators
*See lib/combinators.ts*
`and`: Takes any number of validators. Checks that final input is validated by all of them. Returns the erroneous result, if any.
`or`: Takes any number of validators. Checks that final input is validated by at least one of them. Returns list of errors (positions correspond to validators).
`EagerAnd` and `EagerOr`: Eager variants will run all validators passed to them, no matter what. Logically, they behave the same. Returns a list of errors (if logical result is false).
#### Type Checkers
*See lib/type-checkers.ts*
`checkIf`: Takes an input. Checks if it meets the type criteria. Covers all JS Types, definitive-ness, and existence.
`optional`: Takes a validator. Returns any error(s) from the validation, which only runs if the final input is not null, undefined, or NaN.
#### Collection Checkers
*See lib/object.ts and lib/list.ts*
These create convenient nest-able validators for objects, lists, and tuples. See in-code documentation for usage instructions.
`makeObjectChecker`: Returns object of errors. Properties correspond to bad properties on input object.
`makeListChecker`: Returns list of errors. Positions correspond to bad elements.
`makeTupleChecker`: Returns list of errors. Positions correspond to bad elements.
## Why does this exist?
Probably because I couldn't find the right packages at the right time. [Zod](https://github.com/colinhacks/zod) is great for schema definition, manipulation, and parsing, and [tRPC](https://github.com/trpc/trpc) is good for front-to-backend type-safe http API's.
Zod is fun-ov's closest neighbor, but they differ in meaningful ways.
`fun-ov` isn't a tool or a framework. It's an idea and a pattern, with helpers to cut through annoying details and boilerplate.
It can replicate some of zod's functionality and do some things it can't (context-aware validation, more error cases/types), but it's smaller and less intrusive than zod.
There isn't a tool to learn with `fun-ov`, just a pretty powerful idea made accessible. Fun-ov is a library of validation combinators that you can extend past validation use-cases.
If the Wikipedia entry on combinators makes your eyes glaze over, this [SO question](https://stackoverflow.com/questions/7533837/explanation-of-combinators-for-the-working-man) is a good place to learn about them.
This package was created because validation is a recurring need, and existing solutions at the time of development
didn't meet my standards/needs for style, modularity, customizability, and extensibility.## Future
Possible API changes:
- `makeMapChecker` - excluded because keys/values can be validated before insertion