Gathering detailed insights and metrics for json-schema-to-yup
Gathering detailed insights and metrics for json-schema-to-yup
Gathering detailed insights and metrics for json-schema-to-yup
Gathering detailed insights and metrics for json-schema-to-yup
schema-to-yup
Build a Yup schema object to validate models from a domain model schema (JSON or GraphQL)
@sodaru/yup-to-json-schema
Library to convert Yup to JSON Schema
json-schema-yup-validator
A couple of utils that allows to convert json schema to yup schema and validate data against it. Core features: cross-field validation, internationalization
fst-yup-to-json-schema
Library to convert Yup to JSON Schema with support condtional templates
npm install json-schema-to-yup
Typescript
Module System
Node Version
NPM Version
JavaScript (100%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
NOASSERTION License
287 Stars
366 Commits
52 Forks
8 Watchers
26 Branches
16 Contributors
Updated on May 12, 2025
Latest Version
1.8.8
Package Id
json-schema-to-yup@1.8.8
Unpacked Size
369.23 kB
Size
110.21 kB
File Count
35
NPM Version
6.5.0
Node Version
11.0.0
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
3
4
Build a Yup schema from a JSON Schema, GraphQL schema (type definition) or any other similar type/class and field/properties model or schema :)
The builder currently supports the most commonly used JSON Schema layout and GraphQL type definition exports using graphSchemaToJson (see GraphQL schema).
It also supports some extra convenience schema properties that make it more "smooth" to define validation requirements declaratively (see below).
According to the JSON schema specs, you are free to add extra metadata to the field schema definitions beyond those supported "natively".
Install
npm install json-schema-to-yup -S
or yarn add json-schema-to-yup
Use
1const schema = { 2 $schema: "http://json-schema.org/draft-07/schema#", 3 $id: "http://example.com/person.schema.json", 4 title: "Person", 5 description: "A person", 6 type: "object", 7 properties: { 8 name: { 9 description: "Name of the person", 10 type: "string" 11 }, 12 email: { 13 type: "string", 14 format: "email" 15 }, 16 fooorbar: { 17 type: "string", 18 matches: "(foo|bar)" 19 }, 20 age: { 21 description: "Age of person", 22 type: "number", 23 exclusiveMinimum: 0, 24 required: true 25 }, 26 characterType: { 27 enum: ["good", "bad"], 28 enum_titles: ["Good", "Bad"], 29 type: "string", 30 title: "Type of people", 31 propertyOrder: 3 32 } 33 }, 34 required: ["name", "email"] 35}; 36 37const config = { 38 // for error messages... 39 errMessages: { 40 age: { 41 required: "A person must have an age" 42 }, 43 email: { 44 required: "You must enter an email address", 45 format: "Not a valid email address" 46 } 47 } 48}; 49 50const { buildYup } = require("json-schema-to-yup"); 51const yupSchema = buildYup(json, config); 52// console.dir(schema) 53const valid = await yupSchema.isValid({ 54 name: "jimmy", 55 age: 24 56}); 57 58console.log({ 59 valid 60}); 61// => {valid: true}
This would generate the following Yup validation schema:
1const schema = yup.object().shape({ 2 name: yup.string().required(), 3 age: yup 4 .number() 5 .required() 6 .positive() 7});
Note the "required": true
for the age
property (not natively supported by JSON schema).
strict
default
nullable
required
notRequired
oneOf
(enum
)notOneOf
ensure
compact
items
(of
)maxItems
(max
)minItems
(min
)No keys
maxDate
(max
)minDate
(min
)integer
moreThan
(exclusiveMinimum
)lessThan
(exclusiveMaximum
)positive
negative
min
(minimum
)max
(maximum
)truncate
round
camelCase
constantCase
noUnknown
(propertyNames
)minLength
(min
)maxLength
(max
)pattern
(matches
or regex
)email
(format: 'email'
)url
(format: 'url'
)lowercase
uppercase
trim
Here a more complete example of the variations currently possible
1{ 2 "title": "Person", 3 "description": "A person", 4 "type": "object", 5 "properties": { 6 "name": { 7 "description": "Name of the person", 8 "type": "string", 9 "required": true, 10 "matches": "[a-zA-Z- ]+", 11 "mix": 3, 12 "maxLength": 40, 13 }, 14 "age": { 15 "description": "Age of person", 16 "type": "integer", 17 "moreThan": 0, 18 "max": 130, 19 "default": 32, 20 "required": false, 21 "nullable": true 22 }, 23 "birthday": { 24 "type": "date", 25 "min": "1-1-1900", 26 "maxDate": "1-1-2015" 27 }, 28 "married": { 29 "type": "boolean" 30 }, 31 "boss": { 32 "type": "object", 33 "noUnknown": [ 34 "name" 35 ], 36 "properties": { 37 "name": { 38 "type": "string", 39 "notOneOf": ["Dr. evil", "bad ass"] 40 } 41 } 42 }, 43 "colleagues": { 44 "type": "array", 45 "items": { 46 "type": "object", 47 "propertyNames": [ 48 "name" 49 ], 50 "properties": { 51 "name": { 52 "type": "string" 53 } 54 } 55 } 56 }, 57 "programming": { 58 "type": "object", 59 "properties": { 60 "languages": { 61 "type": "array", 62 "of": { 63 "type": "string", 64 "enum": ["javascript", "java", "C#"] 65 }, 66 "min": 1, 67 "max": 3 68 } 69 } 70 } 71 } 72 } 73}
This library now also supports non JSON schema models. See the types/defaults
mappings.
types/defaults/json-schema.js
1module.exports { 2 getProps: obj => obj.properties, 3 getType: obj => obj.type, 4 getName: obj => obj.name || obj.title, 5 getConstraints: obj => obj, 6 isString: obj => obj.type === "string", 7 isArray: obj => obj.type === "array", 8 isInteger: obj => obj.type === "integer", 9 isBoolean: obj => obj.type === "boolean", 10 hasDateFormat: obj => ["date", "date-time"].find(t => t === obj.format), 11 isDate: obj => obj.type === "string" && defaults.hasDateFormat(obj.format), 12 isNumber: obj => obj.type === "number" || defaults.isInteger(obj.type), 13 isObject: obj => obj.type === "object", 14 isRequired: obj => obj.required 15};
To support another model, such as GraphQL schema (type definitions) via graphSchemaToJson
Person
1{ 2 Person: { 3 name: 'Person', 4 fields: { 5 name: { 6 type: 'String', 7 directives: { 8 constraints: { 9 minLength: 2 10 } 11 }, 12 isNullable: false, 13 isList: false 14 } 15 } 16 directives: {}, 17 type: 'Object', 18 implements: [] 19 } 20}
Create a map of methods to match your model layout:
1const typeDefConf = { 2 getProps: obj => obj.fields, 3 getType: obj => obj.type, 4 getName: obj => obj.name, 5 getConstraints: obj => (obj.directives || {}).constraints || {}, 6 isString: obj => obj.type === "String", 7 isArray: obj => obj.isList, 8 isInteger: obj => obj.type === "Int", 9 isBoolean: obj => obj.type === "Boolean", 10 isDate: obj => obj.type === "Date" || obj.directives.date, 11 isNumber: obj => obj.type === "Int" || obj.type === "Float", 12 isObject: obj => obj.type === "Object", 13 isRequired: obj => !obj.isNullable 14};
Please note that getConstraints
can be used to control where the constraints of the field will be taken from (depending on the type of model/schema or your preference).
Pass overrides to match your model in config
as follows:
1const schema = buildYup(nameJsonSchema, { ...typeDefConf, log: true });
The type definition mappings above are already built-in and available.
To switch the schema type, pass schemaType
in config as follows.
1const schema = buildYup(nameJsonSchema, { schemaType: "type-def", log: true });
Feel free to make PRs to make more common schema models conveniently available!
You can enable logging py passing a log
option in the config
argument. If set to true, it will by default assign the internal log function to console.log
1const schema = buildYup(nameJsonSchema, { log: true });
You can also pass a log function in the log
option to handle log messages and an err
option with a custom error handler function.
See Custom errors in Node for how to design custom errors
1class ValidationError extends Error {} 2 3const schema = buildYup(nameJsonSchema, { 4 log: (name, msg) => console.log(`[${name}] ${msg}`) 5 err: (msg) => { 6 console.error(`[${name}] ERROR: ${msg}` 7 throw new ValidationError(msg) 8 }) 9});
You can supply a createYupSchemaEntry
function as an entry in the config
object.
This function will then be used to build each Yup Schema entry in the Yup Schema being built.
Use the Yup Type classes such as types.YupArray
to act as building blocks or create your own custom logic as you see fit.
1const { YupSchemaEntry, buildYup, types } = require("json-schema-to-yup"); 2 3class CustomYupArray extends types.YupArray { 4 // ... 5} 6 7class CustomYupSchemaEntry extends YupSchemaEntry { 8 // ... 9} 10 11function createYupSchemaEntry(key, value, config) { 12 const builder = new CustomYupSchemaEntryBuilder(key, value, config); 13 builder.types.array = config => createYupArray(config); 14 return builder.toEntry(); 15} 16 17// use some localized error messages 18const messages = i18n.locale(LOCALE); 19 20const yupSchema = buildYup(json, { 21 createYupSchemaEntry, 22 messages 23});
You can use extendYupApi
to extend the Yup API with extra validation methods:
1const validator = require("validator"); 2const { extendYupApi } = require("json-schema-to-yup/validator-bridge"); 3 4// by default extends with string format validation methods of validator 5// See https://www.npmjs.com/package/validator 6extendYupApi({ validator });
You can optionally pass in a custom validator
and a constraints map of your choice.
You can either extend the default constraints or override them with your own map.
PS: Check out src/validator-bridge
for more many options for fine control
1const myValidator = new MyValidator(); 2const constraints = ["creditCard", "currency", { name: "hash", opts: "algo" }]; 3extendYupApi({ validator: myValidator, override: true, constraints }); 4 5const { buildYup } = require("json-schema-to-yup"); 6// type def sample schema, using credit-card format validator 7const schema = { 8 name: "BankAccount", 9 fields: { 10 accountNumber: { 11 type: "String", 12 format: "credit-card" 13 } 14 } 15}; 16 17// opt in to use generic string format validation, via format: true config option 18const yupSchema = buildYup(schema, { format: true, schemaType: "type-def" }); 19// ...do your validation 20const valid = await yupSchema.isValid({ 21 accountNumber: "123-4567-1828-2929" 22});
Now the bridge includes tests. Seems to work ;)
You can sublass YupBuilder
or any of the internal classes to create your own custom infrastructure to suit your particular needs, expand with support for extra features etc.
1const { YupBuilder } = require("json-schema-to-yup"); 2 3class MyYupBuilder extends YupBuilder { 4 // ... custom overrides etc 5} 6 7const builder = new MyYupBuilder(schema, config); 8const { yupSchema } = builder; 9// ...
You can pass an errMessages
object in the optional config
object argument with key mappings for your custom validation error messages.
Internally the validator error messages are resolved with the instance method valErrMessage
(from Mixed
class)
1 notOneOf() { 2 const {not, notOneOf} = this.value 3 const $oneOf = notOneOf || (not && (not.enum || not.oneOf)) 4 $oneOf && this 5 .base 6 .notOneOf($oneOf, this.valErrMessage('notOneOf')) 7 return this 8 }
The key entries can be either a function, taking a value
argument or a static string.
Here are some of the defaults that you can override as needed.
1export const errValKeys = [ 2 "oneOf", 3 "enum", 4 "required", 5 "notRequired", 6 "minDate", 7 "min", 8 "maxDate", 9 "max", 10 "trim", 11 "lowercase", 12 "uppercase", 13 "email", 14 "url", 15 "minLength", 16 "maxLength", 17 "pattern", 18 "matches", 19 "regex", 20 "integer", 21 "positive", 22 "minimum", 23 "maximum" 24]; 25 26export const defaults = { 27 errMessages: (keys = errValKeys) => 28 keys.reduce((acc, key) => { 29 const fn = ({ key, value }) => 30 `${key}: invalid for ${value.name || value.title}`; 31 acc[key] = fn; 32 return acc; 33 }, {}) 34};
1const { buildYup, types } = require("json-schema-to-yup"); 2const { defaults } = types; 3 4const myErrMessages = require("./err-messages"); 5const valKeys = ["lowercase", "integer"]; 6 7// by default Yup built-in validation error messages will be used if not overridden here 8const errMessages = { 9 ...defaults.errMessages(valKeys), 10 myErrMessages 11}; 12 13const yupSchema = buildYup(json, { 14 errMessages 15});
See the number
type for the current best practice to add type constraints.
For simple cases: use addConstraint
from the superclass YupMixed
1 required() { 2 return this.addConstraint("required"); 3 }
For types with several of these, we should map through a list or map to add them all.
1 strict() { 2 return this.addValueConstraint("strict"); 3 } 4 5 required() { 6 return this.addConstraint("required"); 7 } 8 9 notRequired() { 10 return this.addConstraint("notRequired"); 11 }
Can be rewritten to use conventions, iterating a map:
1 addMappedConstraints() { 2 Object.keys(this.constraintsMap).map(key => { 3 const list = constraintsMap[key]; 4 const fnName = key === 'value' ? 'addValueConstraint' : 'addConstraint' 5 list.map(this.[fnName]); 6 }); 7 } 8 9 get constraintsMap() { 10 return { 11 simple: ["required", "notRequired", "nullable"], 12 value: ["default", "strict"] 13 }; 14 }
For more complex contraints that:
You can create a separate Constraint
subclass, to offload and handle it all separately.
Here is a sample RangeConstraint
used by number.
1class RangeConstraint extends NumericConstraint { 2 constructor(typer) { 3 super(typer); 4 } 5 6 get $map() { 7 return { 8 moreThan: ["exclusiveMinimum", "moreThan"], 9 lessThan: ["exclusiveMaximum", "lessThan"], 10 max: ["maximum", "max"], 11 min: ["minimum", "min"] 12 }; 13 } 14}
Instead of wrapping a Constraint
you can call it directly with a map
1// this would be an instance such as YupNumber 2// map equivalent to $map in the RangeConstraint 3range() { 4 return createNumericConstraint(this, map); 5}
For the core type constraint class (such as YupNumber
) you should now be able to simplify it to:
1 get enabled() { 2 return ["range", "posNeg", "integer"]; 3 } 4 5 convert() { 6 this.enabled.map(name => this.processConstraint(name)); 7 super.convert(); 8 return this; 9 }
The following constraint classes are available for use:
NumericConstraint
StringConstraint
RegExpConstraint
DateConstraint
Currently only YupNumber
has been (partly) refactored to take advantage of this new infrastructure. Please help refactor the rest!
YupNumber
also has the most unit test coverage, used to test the current infrastructure!
The library JSON Schema model builder is a powerful toolset to build a framework to create any kind of output model from a JSON schema.
If you enjoy this declarative/generator approach, try it out!
Uses jest for unit testing.
NumericConstraint
)Current development is taking place on refactoring branch.
On his branch:
If you would like to further improved this library or add support for more validators than Yup, please help on this branch. Cheers!
Please feel free to come with ideas and suggestions on how to further improve this library.
2018 Kristian Mandrup (CTO@Tecla5)
MIT
No vulnerabilities found.
No security vulnerabilities found.