Skip to content

ritchieanesco/json-schema-yup-transform

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Transform a JSON Schema to Yup Schema

Build Status Coverage Status npm version

A utility to generate a Yup Schema from a valid JSON Schema.

Note: This package only supports yup v0.29.3 and below.

json-schema-yup-transform is heavily inspired by schema-to-yup but strictly supports the draft 7 specification

The main objective is to support as many of the features of the draft 7 specification as possible.

Building

The project is written in TypeScript.

$ yarn build

Output goes into the dist/ directory.

Testing

Tests and code coverage are run with Jest.

$ yarn test

Useful Tools

Supported features

String, Number, Integer, Array, Object, Boolean and Null types are supported. The tables below outline which keywords each schema type supports.

String types

Keyword Supported
const ✔️
enum ✔️
minLength ✔️
maxLength ✔️
pattern ✔️
date-time (format) ✔️
time (format) ✔️
date (format) ✔️
email (format) ✔️
idn-email (format) ✔️
hostname (format) ✔️
idn-hostname (format) ✔️
ipv4 (format) ✔️
ipv6 (format) ✔️
uri (format) ✔️
uri-reference (format) ✔️
iri (format) ✖️
iri-reference (format) ✖️
uri-template (format) ✖️
json-pointer ✖️
relative-json-pointer ✖️
regex ✔️

Number and Integer types

Keyword Supported
const ✔️
enum ✔️
multipleOf ✔️
minimum ✔️
exclusiveMinimum ✔️
maximum ✔️
exclusiveMaximum ✔️

Array types

Keyword Supported
const ✔️
enum ✔️
items ✔️
contains ✔️
tuple ✔️
additionalItems ✖️
minItems ✔️
maxItems ✔️
uniqueItems ✔️

Boolean types

Keyword Supported
const ✔️

Object types

Keyword Supported
required ✔️
properties ✔️
additionalProperties ✖️
propertyNames ✖️
size ✖️
dependencies ✖️
patternProperties ✖️

Generic keywords

Keyword Supported
default ✔️
description (used to store node path) ✔️
if ✔️
then ✔️
else ✔️
definitions ✔️
$id ✔️

Extending Schemas

Keyword Supported
allOf ✔️
anyOf ✔️
oneOf ✔️
not ✔️

Usage

Provide a valid schema and convertToYup will transform it to a yup schema.

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "example",
  title: "Example",
  properties: {
    name: {
      type: "string"
    }
  }
};

// the yup equivalent of the above json schema
// const yupschema = Yup.object().shape({
//     name: Yup.string()
// })

// check validity

const yupschema = convertToYup(schema);
const isValid = yupschema.isValidsync({
  name: "Bruce Tanek"
});
// => true

Applying conditional rules

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "example-conditional-rules",
  title: "Example of conditional rules",
  properties: {
    country: {
      type: "string"
    }
  },
  required: ["country"]
  if: {
      properties: {
          country: {
            const: "Australia"
          }
      }
  }
  then: {
      properties: {
          residencyYears: {
              type: "number",
              minimum: 12
          }
      },
      required: ["residencyYears"]
  }
};

// the yup equivalent of the above json schema
// const yupschema = Yup.object().shape({
//     country: Yup.string().required(),
//     residencyYears: Yup.number().when('country', {
//      is: 'true'
//      then: Yup.number().required()
//    })
// })

// check validity

const yupschema = convertToYup(schema)
const isValid = yupschema.isValidsync({
    country: "Australia",
    residencyYears: 15
})
// => true

Applying multiple types

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "example-multiple-types",
  title: "Example of multiple types",
  properties: {
    name: {
      type: ["string", "null"]
    }
  }
};

// the yup equivalent of the above json schema
// const yupschema = Yup.object().shape({
//     name: Yup.lazy(value => {
//       switch (typeof value) {
//          case 'string':
//              return Yup.number();
//          case 'null':
//              return Yup.mixed().notRequired();
//          default:
//              return Yup.mixed();
//       }
//    })
// })

// check validity

const yupschema = convertToYup(schema);
const isValid = yupschema.isValidsync({
  name: null
});
// => true

Providing custom error messages

The structure of the configuration error messages need to adhere to the path of that field in the schema as well as the associated schema validation keyword.

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "example-custom-error-messages",
  title: "Exampel of custom error messages",
  properties: {
    team: {
      type: "object",
      properties: {
        name: {
          type: "string"
        }
      }
    }
  },
  required: ["name"]
};

// configuration for custom error messages

const config = {
  errors: {
    team: {
      name: {
        required: "Custom error message"
      }
    }
  }
};

// check validity
const yupschema = convertToYup(schema, config);
let errorMessage;
try {
  errorMessage = yupschema.validateSync();
} catch (e) {
  errorMessage = e.errors[0];
}
// => "Custom error message"

Using error handlers to further customise error messages

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "example-custom-error-messages",
  title: "Exampel of custom error messages",
  properties: {
    team: {
      type: "object",
      properties: {
        name: {
          type: "string"
        }
      }
    }
  },
  required: ["name"]
};

// configuration for custom error messages

const config = {
  errors: {
    team: {
      name: {
        required: ([key, { required }]) =>
          `${key} field is invalid. Here is a list of required fields: ${required}`
      }
    }
  }
};

// check validity
const yupschema = convertToYup(schema, config);
let errorMessage;
try {
  errorMessage = yupschema.validateSync();
} catch (e) {
  errorMessage = e.errors[0];
}
// => "name field is invalid. Here is a list of required fields: name"

Setting default error messages for a type

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "example-default-error-messages",
  title: "Example of default error messages",
  properties: {
    team: {
      type: "object",
      properties: {
        name: {
          type: "string"
        }
      }
    }
  }
};

// set default error message for type of string

const config = {
  errors: {
    defaults: {
      string: "Custom error message"
    }
  }
};

// check validity
const yupschema = convertToYup(schema, config);
let errorMessage;
try {
  errorMessage = yupschema.validateSync({
    team: {
      name: null
    }
  });
} catch (e) {
  errorMessage = e.errors[0];
}
// => "Custom error message"

Applying definitions and $ref

import convertToYup from "json-schema-yup-transformer";

let schema: JSONSchema7 = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "example-definitions",
  title: "Example of definitions",
  definitions: {
    address: {
      type: "object",
      properties: {
        street_address: { type: "string" },
        city: { type: "string" },
        state: { type: "string" }
      },
      required: ["street_address", "city", "state"]
    }
  },
  properties: {
    mailingAddress: {
      $ref: "#/definitions/address"
    }
  }
};

// check validity
const yupschema = convertToYup(schema);
const isValid = yupschema.isValidsync({
  mailingAddress: {
    street_address: "18 Rover street",
    city: "New York City",
    state: "New York"
  }
});
// => true

Validate against allof subschemas

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "test",
  title: "Test",
  properties: {
    things: {
      allOf: [
        { type: "string", minLength: 4 },
        { type: "string", maxLength: 6 }
      ]
    }
  }
};

// check validity
let yupschema = convertToYup(schema);
let isValid = yupschema.isValidSync({
  things: "12345"
});
// => true

Validate against anyof subschemas

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "test",
  title: "Test",
  properties: {
    things: {
      anyOf: [
        { type: "string", minLength: 6 },
        { type: "string", const: "test" }
      ]
    }
  }
};

// check validity
let yupschema = convertToYup(schema);
let isValid = yupschema.isValidSync({
  things: "test"
});
// => true

Validate against not subschemas

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "test",
  title: "Test",
  properties: {
    things: {
      not: { type: "string", minLength: 6 }
    }
  }
};

// check validity
let yupschema = convertToYup(schema);
let isValid = yupschema.isValidSync({
  things: "1234"
});
// => true

Validate against oneof subschemas

import convertToYup from "json-schema-yup-transformer";

const schema = {
  type: "object",
  $schema: "http://json-schema.org/draft-07/schema#",
  $id: "test",
  title: "Test",
  properties: {
    things: {
      oneOf: [
        { type: "string", minLength: 6 },
        { type: "string", minLength: 3 }
      ]
    }
  }
};

// check validity
let yupschema = convertToYup(schema);
let isValid = yupschema.isValidSync({
  things: "1234"
});
// => true