Skip to content

Instantly share code, notes, and snippets.

@stefan-vatov
Created June 13, 2021 03:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stefan-vatov/ce870af97844548bca12f46e6862b1ef to your computer and use it in GitHub Desktop.
Save stefan-vatov/ce870af97844548bca12f46e6862b1ef to your computer and use it in GitHub Desktop.
[Validation with folktale]
import { IBasicObject } from './objects';
export interface IValidator<T> {
run: IValidatorRun<T>;
concat: (other: IValidator<T>) => IValidator<T>;
}
export type ValidatorTypes = [] | undefined | string;
export type IValidatorRun<T> = (key: string, x: T, rec: IBasicObject) => IValidator<T>;
export interface IValidationResult {
validationError: IBasicObject | undefined;
validationResult: IBasicObject | undefined;
}
export type IMiddlewareValidator = (body: IBasicObject) => IBasicObject;
// @ts-ignore
import { List } from 'immutable-ext';
// @ts-ignore
import Validation from 'folktale/validation';
import { IBasicObject } from '../../interfaces/objects';
import { IValidator, IValidatorRun } from '../../interfaces/IValidator';
import { VALID_REL_TRANSITIONS } from '../transitions/constants';
const { Success, Failure } = Validation;
// tslint:disable-next-line:no-object-literal-type-assertion
export const Validator = <T>(run: IValidatorRun<T>): IValidator<T> =>
({
run,
concat: (other: IValidator<T>) => Validator((key, x, rec) => run(key, x, rec).concat(other.run(key, x, rec))),
} as IValidator<T>);
export const validate = (spec: IBasicObject, record: IBasicObject) =>
List(Object.keys(spec)).foldMap((key: string) => spec[key].run(key, record[key], record), Success([record]));
export const isPresent = Validator<any>((key, x, rec) =>
!!x ? Success([rec]) : Failure([`'${key}' must be present`])
);
export const isArray = Validator<any>((key, x, rec) =>
Array.isArray(x) ? Success([rec]) : Failure([`'${key}' must be an array`])
);
export const isArrayOfType = (type: string) =>
Validator<any>((key, x, rec) =>
x?.length > 0 &&
x.map((item: any) => typeof item === type).reduce((acc: boolean, curr: boolean) => acc && curr, true)
? Success([rec])
: Failure([`'${key}' must be an array of ${type}s`])
);
export const isArrayOfStrings = isArrayOfType('string');
export const isArrayOfNumbers = isArrayOfType('number');
export const isArrayOfObjects = isArrayOfType('object');
export const isArrayOfStringsStartingWith = (substring: string) =>
Validator<any>((key, x, rec) =>
x?.length > 0 &&
x.map((item: any) => item.indexOf(substring) === 0).reduce((acc: boolean, curr: boolean) => acc && curr, true)
? Success([rec])
: Failure([`'${key}' must be an array of strings starting with ${substring}`])
);
export const isString = Validator<any>((key, x, rec) =>
typeof x === 'string' ? Success([rec]) : Failure([`'${key}' must be a string`])
);
import { IBasicObject } from '../../interfaces/objects';
// @ts-ignore
import { List } from 'immutable-ext';
// @ts-ignore
import Validation from 'folktale/validation';
import { IValidationResult } from '../../interfaces/IValidator';
import {
isArray,
isArrayOfStrings,
isPresent,
isString,
noDuplicates,
validate,
} from './index';
const { Success, Failure } = Validation;
export const validateSomeInputs = (requestBody: IBasicObject): IValidationResult => {
const spec: IBasicObject = {
name: isPresent.concat(isString),
version: isPresent.concat(isString),
regions: isPresent.concat(isArray).concat(isArrayOfStrings).concat(noDuplicates),
};
return validate(spec, requestBody);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment