1.0.17 • Published 2 years ago

mikamin2 v1.0.17

Weekly downloads
-
License
MIT
Repository
-
Last release
2 years ago

Schema based validation library

Zoply Schema lightweight schema builder for value parsing and synchronous validation.

Getting Started

Installation

# Install with yarn
yarn add zoply-schema

# Install with npm
npm install zoply-schema --save

Usage

You define and create schema objects. Schema objects are immutable, so each call of a method returns a new schema object. Basic schema definition:

import {
  bool,
  numeric,
  required,
  nullable,
  requiredList,
  each,
  optional,
  handleSchema,
} from 'libs/vladik-schema'

enum Gender {
  Man = 0,
  Woman = 1,
}

interface FeedSearch {
  ids?: string[]
  genders: Gender[]
  cityId: number | null
  addiction?: number
  age: {
    from: number
    to: number
  }
  hasPhoto: boolean
}
const searchSchema = {
  ids: each(required),
  genders: each(required, requiredList),
  cityId: nullable(required),
  addiction: optional([required, numeric]),
  age: {
    from: [required, numeric],
    to: [required, numeric],
  },
  hasPhoto: bool,
}

// check validity
const errors = handleSchema({
  schema: searchSchema,
  values: {
    genders: [1],
    cityId: '327',
  },
})

const hasError = Object.keys(errors).length != 0

console.log(errors)
// => {
//   age: { from: 'from is required!', to: 'to is required!' },
//   hasPhoto: 'hasPhoto must be boolean!'
// }

Using a custom locale dictionary

When you call handleSchema, he have parametr fromatter, and you able to detect user language, and after just

const formatErrorMsg = (lang: Language): ErrorFormater => ({ rule, name, meta }) => {
  const dictionary = dictionaries[lang]

  switch (rule) {
    case 'required':
      return dictionary.REQUIRED.replace('#name#', name)
    case 'requiredList':
      return dictionary.REQUIRED_LIST.replace('#name#', name)
    case 'optional':
      return dictionary.OPTIONAL.replace('#name#', name)
    case 'array':
      return dictionary.ARRAY.replace('#name#', name)
    case 'email':
      return dictionary.EMAIL.replace('#name#', name)
    case 'number':
      return dictionary.NUMBER.replace('#name#', name)
    case 'oneOf':
      return dictionary.ONE_OF
        .replace('#name#', name)
        .replace('#meta#', meta!.values.join(', '))
    default:
      return dictionary.UNKNOWN
  }
}

// Validation
const errors = handleSchema({
  schema,
  values: req.body,
  formater: formatErrorMsg(req.lang),
})

Fastify integration

type Validate<T> = preHandlerHookHandler<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, { Body: T }>

export const zoplyValidate = (schema: any): Validate<any> => (req, res, done) => {
  req.lang = parseAcceptLanguage(req.headers['accept-language']!)

  const errors = handleSchema({
    schema,
    values: req.body,
    formater: formatErrorMsg(req.lang),
  })

  if (Object.keys(errors).length != 0) {
    return res.status(400).send({
      errors,
    })
  }

  done()
}

And use it in handler:

// handler.ts
import * as input from './input'

fastify.route<{ Body: input.Register }>({
  url: '/register',
  method: 'POST',
  preHandler: zoplyValidate(input.registerSchema),
  handler: req => services.AuthService.register(req.body),
})

// input.ts
export interface Register {
  username: string
  email: string
  password: string
}
export const registerSchema = {
  username: required,
  email: [required, email],
  password: required,
}
1.0.17

2 years ago

1.0.16

2 years ago

1.0.15

2 years ago

1.0.14

2 years ago

1.0.13

2 years ago

1.0.12

2 years ago

1.0.11

2 years ago

1.0.10

2 years ago

1.0.9

2 years ago

1.0.8

2 years ago

1.0.7

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago