Validates content against schema. No eval or new Function. CSP friendly.
npm install @datadayrepos/json-schema-validatorjson-validator and json-schema utilities for traversal, data generation and validation
Largely based on json-schema-library https://github.com/sagold/json-schema-library/blob/main/package.json
The version is made for supply chain safety reasons and need for some custom optimization and functionality.
- CSP friendly, no eval
Edits to original:
- no external dependencies
- types script improvements
``sh`
pnpm install @datadayrepos/json-schema-validator
This text below is is from the original repo except the first sections marked (IS).
- Impportant: original is also converted to NODE next module with explicitt import syntax.
`ts
import { Draft07 } from '@datadayrepos/json-schema-validator' // This is validator instance for json-schema version 7
import type {ValidatorType} from '@datadayrepos/json-schema-validator' // shortened minimal spec that is consistent with Draft
const validator = createValidatorInstance() // NEW: this makes the validator available at the root of the module and saves time on instantiation
function createValidatorInstance():ValidatorType{
const v = new Draft07() // we dont need to pass in a schema here - contrary to the specs in the original
// we can pass in customizations similar to the original - in that case, use an empty {} as schema value when creating the instance
return v
}
// standard application method for triggering the validation
function myValidatorWithErrorMessages({
validator, // the validator is passed in
formData, // data to be validated
schema, // schema to be validated
rootSchema=schema, // master schema to be validated
uiSchema = {},
// transformErrors,
// additionalMetaSchemas = [],
// customFormats = {},
errorSchema = {},
required = false, // flag passed in from ui function
propPath = '',
// isOnlyFirstError = true, // Take only the first error message
isRoot = false,
}: {
validator: ValidatorType
formData: any
schema: ABYSchema
rootSchema?:ABYSchema
uiSchema?: UISchema // Ensure this is the correct type
errorSchema?: ErrSchema // Ensure this is the correct type // transformErrors?: ErrorTransformer;
// additionalMetaSchemas?: CustomValidatorOptionsType["additionalMetaSchemas"];
// customFormats?: CustomValidatorOptionsType["customFormats"];
required?: boolean
propPath?: string
// isOnlyFirstError: boolean;
isRoot?: boolean
}): JsonError[] {
// any pre-processing needed
// validator
const errors: JsonError[] = validator.validateFormData(
formData,
schema,
rootSchema, // this is optional
)
// Alternative method for bool results
const isValid: boolean= validator.isValidFormData(
formData,
schema,
rootSchema, // this is optional
)
}
`
Other methods below are also valid.
usage
json-schema-library exposes a Draft for most json-schema drafts. Each Draft can be instantiated and offers a common set of actions working on the specified json-schema version. Example:
`ts
import { Draft, Draft04, Draft06, Draft07, JsonError } from 'json-schema-library'
import myJsonSchema from './myJsonSchema.json'
import myData from './myData.json'
const jsonSchema: Draft = new Draft07(myJsonSchema)
const errors: JsonError[] = jsonSchema.validate(myData)
`
What follows is a description of the main draft methods.
- validate
- isValid
- validateAsync
- getTemplate
- each
- eachSchema
- getSchema
- getChildSchemaSelection
- step
- addRemoteSchema
- createSchemaOf
- compileSchema
validate is a complete _json-schema validator_ for your input data. Calling _validate_ will return a list of validation errors for the passed data.
`ts`
const jsonSchema = new Draft07(myJsonSchema)
const errors: JsonError[] = jsonSchema.validate(myData)
Additionally, you can validate a sub-schema and its data. Doing this, the intial schema will be used as rootSchema (for example, to resolve $ref from _definitions_).
`ts`
const jsonSchema = new Draft07(myJsonSchema)
const errors: JsonError[] = jsonSchema.validate('my-string', { type: 'number' })
> To prevent some errors when using helper methods with an independent sub-schema, please use compileSchema if it is not retrieved from a draft-method directly (which was compiled by passing it to Draft). Specifically, if the schema contains a $ref you need to use compileSchema. More details in compileSchema.
About type JsonError
In json-schema-library all errors are in the format of a JsonError:
`ts`
type JsonError = {
type: 'error'
name: string
code: string
message: string
data?: { [p: string]: any }
}
In almost all cases, a _json-pointer_ is given on _error.data.pointer_, which points to the source within data where the error occured.
For more details on how to work with errors, refer to section custom errors.
Example
`ts
import { Draft07, JsonError, JsonSchema } from 'json-schema-library'
const myJsonSchema: JsonSchema = {
type: 'object',
additionalProperties: false
}
const jsonSchema = new Draft07(myJsonSchema)
const errors: JsonError[] = jsonSchema.validate({ name: 'my-data' })
expect(errors).to.deep.equal([
{
type: 'error',
name: 'NoAdditionalPropertiesError',
code: 'no-additional-properties-error',
message: 'Additional property name in # is not allowed',`
data: { property: 'name', properties: [], pointer: '#' }
}
])
Example with separate schema
`ts
import { Draft07, JsonError, JsonSchema } from 'json-schema-library'
const myJsonSchema: JsonSchema = {
type: 'object',
additionalProperties: false
}
const jsonSchema = new Draft07(myJsonSchema)
const mySchema = jsonSchema.compileSchema({ type: 'number' })
const errors: JsonError[] = jsonSchema.validate('my-string', mySchema)
expect(errors).to.deep.equal([
{
type: 'error',
name: 'TypeError',
code: 'type-error',
message: 'Expected my-string (string) in # to be of type number',`
data: {
received: 'string',
expected: 'number',
value: 'my-string',
pointer: '#'
}
}
])
isValid will return true if the given json-data is valid against the json-schema.
`ts`
const jsonSchema = new Draft07(myJsonSchema)
const isValid: boolean = jsonSchema.isValid(myData)
> This method is not yet exposed by a draft directly as the API of this is yet unsatisfactory. Nonetheless, this function is in production and can be used reliably.
Optional support for onError helper, which is invoked for each error (after being resolved):
`ts
import { Draft07, JsonError, validateAsync } from 'json-schema-library'
const draft = new Core(mySchema)
validateAsync(draft, '', { onError: (err: JsonError) => {}, schema: draft.getSchema() }).then(
(allErrors: JsonError[]) => {}
)
`
getTemplate creates input data from a json-schema that is valid to the schema. Where possible, the json-schema default property will be used to initially setup input data. Otherwise, the first values encountered (enum values, initial values, etc.) are user to build up the json-data.
`ts`
const jsonSchema = new Draft07(myJsonSchema)
const myData = jsonSchema.getTemplate()
Additionally, you can pass input data. getTemplate will then complement any missing values from the schema, while keeping the initial values.
`ts`
const jsonSchema = new Draft07(myJsonSchema)
const myData = jsonSchema.getTemplate({ name: 'input-data' })
Note If you are using references in your schema, getTemplate will only resolve the first _$ref_ in each path, ensuring no inifinte data structures are created. In case the limit of 1 _$ref_ resolution is too low, you can modify the value globally one by adjusting the json-schema-library settings:
`ts`
import { settings } from "json-schema-library";
settings..GET_TEMPLATE_RECURSION_LIMIT = 5;
Example
`ts
import { Draft07, JsonSchema } from 'json-schema-library';
const myJsonSchema: JsonSchema = {
type: 'object',
required: ['name', 'option', 'list'],
properties: {
name: { type: 'string' },
option: {
type: 'string',
enum: ['first-option', 'second-option']
},
list: {
type: 'array',
items: {
type: 'string',
default: 'new item'
},
minItems: 1
}
}
};
const jsonSchema = new Draft07(myJsonSchema);
const myData = jsonSchema.getTemplate();
expect(myData).to.deep.equal({
name: ',
option: 'first-option',
list: ['new item']
});
`
Example with input data
`ts
import { Draft07, JsonSchema } from 'json-schema-library'
const myJsonSchema: JsonSchema = {
type: 'object',
required: ['name', 'option', 'list'],
properties: {
name: { type: 'string' },
option: {
type: 'string',
enum: ['first-option', 'second-option']
},
list: {
type: 'array',
items: {
type: 'string',
default: 'new item'
},
minItems: 1
}
}
}
const jsonSchema = new Draft07(myJsonSchema)
const myData = jsonSchema.getTemplate({ name: 'input-data', list: [] })
expect(myData).to.deep.equal({
name: 'input-data',
option: 'first-option',
list: ['new item']
})
`
each iterates over each data-item (_object_, _array_ and _value_) and emits the data-item, schema and location to a callback.
`ts`
const jsonSchema = new Draft07(mySchema)
function myCallback(schema: JsonSchema, value: unknown, pointer: JsonPointer) {
console.log(schema, value, pointer)
}
jsonSchema.each(myData, myCallback)
Example
`ts
import { Draft07, JsonPointer, JsonSchema } from 'json-schema-library'
const mySchema: JsonSchema = {
type: 'array',
items: [{ type: 'number' }, { type: 'string' }]
}
const jsonSchema = new Draft07(mySchema)
const calls = []
function myCallback(schema: JsonSchema, value: unknown, pointer: JsonPointer) {
calls.push({ schema, value, pointer })
}
jsonSchema.each([5, 'nine'], myCallback)
expect(calls).to.deep.equal([
{ schema: mySchema, value: [5, 'nine'], pointer: '#' },
{ schema: { type: 'number' }, value: 5, pointer: '#/0' },
{ schema: { type: 'string' }, value: 'nine', pointer: '#/1' }
])
`
eachSchema emits each sub-schema definition to a callback.
`ts`
const jsonSchema = new Draft07(mySchema)
function myCallback(schema: JsonSchema) {
console.log(schema)
}
jsonSchema.eachSchema(myCallback)
Example
`ts
import { Draft07, JsonSchema } from 'json-schema-library'
const mySchema: JsonSchema = {
type: 'array',
items: {
oneOf: [{ type: 'number' }, { $ref: '#/$defs/value' }]
},
$defs: {
value: { type: 'string' },
object: { type: 'object' }
}
}
const jsonSchema = new Draft07(mySchema)
const calls = []
function myCallback(schema: JsonSchema) {
calls.push(schema)
}
jsonSchema.eachSchema(myCallback)
expect(calls).to.deep.equal([
mySchema,
{ oneOf: [{ type: 'number' }, { $ref: '#/$defs/value' }] },
{ type: 'number' },
{ $ref: '#/$defs/value' },
{ type: 'string' },
{ type: 'object' }
])
`
getSchema retrieves the json-schema of a specific location in data. The location in data is given by a _json-pointer_. In many cases the json-schema can be retrieved without passing any data, but in situations where the schema is dynamic (for example in _oneOf_, _dependencies_, etc.), the data is required or will return a _JsonError_ if the location cannot be found.
`ts`
const jsonSchema = new Draft07(mySchema)
let schemaOfName: JsonSchema | JsonError | undefined
schemaOfName = jsonSchema.getSchema({ pointer: '/list/1/name', data: myData })
Note that getSchema will return undefined for paths that lead to valid properties, but miss a schema definition. For example:
`ts`
const jsonSchema = new Draft07({ type: 'object' })
const schemaOfName = jsonSchema.getSchema({ pointer: '/name' })
console.log(schemaOfName) // undefined
In case this is unwanted behaviour, use the withSchemaWarning option to return a json-error with code schema-warning instead:
`ts`
const jsonSchema = new Draft07({ type: 'object' })
const schemaOfName = jsonSchema.getSchema({ pointer: '/name', withSchemaWarning: true })
console.log(schemaOfName) // { type: "error", code: "schema-warning" }
Example
`ts
import { Draft07, JsonError, JsonSchema } from 'json-schema-library'
const mySchema = {
type: 'object',
properties: {
list: {
type: 'array',
items: {
oneOf: [
{
type: 'object',
required: ['name'],
properties: {
name: {
type: 'string',
title: 'name of item'
}
}
},
{
type: 'object',
required: ['description'],
properties: {
description: {
type: 'string',
title: 'description of item'
}
}
}
]
}
}
}
}
const jsonSchema = new Draft07(mySchema)
let schemaOfItem: JsonSchema | JsonError | undefined
schemaOfItem = jsonSchema.getSchema({
pointer: '/list/1',
data: {
list: [{ description: '...' }, { name: 'my-item' }]
}
})
expect(schemaOfItem).to.deep.equal({
type: 'object',
required: ['name'],
properties: {
name: {
type: 'string',
title: 'name of item'
}
}
})
`
Evaluating errors
All returned json-errors have a data property with the following properties
- pointer json-pointer to the location where the error occured. In case of omitted data, this is the last json-schema location that could be resolvedschema
- the json-schema of the last resolved location and the source of the errorvalue
- the data value at this location that could not be resolved
`ts`
const schema = jsonSchema.getSchema({ pointer: '/list/1' })
if (isJsonError(schema))
console.log(Object.keys(schema.data)) // [pointer, schema, value]
About JsonPointer
Json-Pointer defines a string syntax for identifying a specific value within a Json document and is supported by Json-Schema. Given a Json document, it behaves similar to a lodash path (a[0].b.c), which follows JS-syntax, but instead uses / separators (e.g., a/0/b/c). In the end, you describe a path into the Json data to a specific point.
getChildSchemaSelection returns a list of available sub-schemas for the given property. In many cases, a single schema will be returned. For _oneOf_-schemas, a list of possible options is returned.
This helper always returns a list of schemas.
Note This helper currenly supports a subset of json-schema for multiple results, mainly _oneOf_-definitions
`ts`
const jsonSchema = new Draft07(mySchema)
const schemas: JsonSchema[] = jsonSchema.getChildSchemaSelection('content', localSchema)
Example
`ts
import { Draft07, JsonError, JsonSchema } from 'json-schema-library'
const jsonSchema = new Draft07()
const localSchema = {
type: 'object',
properties: {
content: {
oneOf: [{ type: 'string' }, { type: 'number' }]
}
}
}
const schemas: JsonSchema[] = jsonSchema.getChildSchemaSelection('content', localSchema)
expect(schemas).to.deep.equal([{ type: 'string' }, { type: 'number' }])
`
step retrieves the json-schema of a child property or index. Using step it is possible to incrementally go through the data, retrieving the schema for each next item.
`ts`
const jsonSchema = new Draft07(mySchema)
const localSchema = { type: 'object', properties: { title: { type: 'string' } } }
const localData = { title: 'value' }
const schemaOfTitle = jsonSchema.step('title', localSchema, localData)
Example
`ts
import { Draft07, JsonError, JsonSchema } from 'json-schema-library'
const jsonSchema = new Draft07(mySchema)
const localSchema = {
oneOf: [
{
type: 'object',
properties: { title: { type: 'string' } }
},
{
type: 'object',
properties: { title: { type: 'number' } }
}
]
}
const localData = { title: 4 }
const schemaOfTitle = jsonSchema.step('title', localSchema, localData)
expect(res).to.deep.eq({ type: 'number' })
`
addRemoteSchema lets you add additional schemas that can be referenced by an URL using $ref. Use this to combine multiple schemas without changing the actual schema.
Each schemas is referenced by their unique $id (since draft-06, previously id). Usually an $id is specified as an url, for example https://mydomain.com/schema/schema-name or with a file extension like https://mydomain.com/schema/schema-name.json. At least in json-schema-library you can use any name, just ensure the $id is unique across all schemas.
To add a remote schema use the exposed method addRemoteSchema:
`ts
const jsonSchema = new Draft07()
jsonSchema.addRemoteSchema('https://sagold.com/remote', {
$id: 'https://sagold.com/remote',
title: 'A character',
type: 'string',
minLength: 1,
maxLength: 1
})
`
Note the given _url_ and $id on the root schema should match. If $id is omitted it will be added from the passed url.
To access the remote schema, add a $ref within your local schema
`ts`
jsonSchema.setSchema({
$id: 'https://sagold.com/local',
type: 'object',
required: ['character'],
properties: {
character: {
$ref: 'https://sagold.com/remote'
}
}
})
and the remote schema will be resolved automatically:
`ts`
jsonSchema.validate({ character: 'AB' }) // maxLength error
jsonSchema.getTemplate({}) // { character: "A" } - default value resolved
// returns remote schema (from compiled local schema):
jsonSchema.getSchema().getRef('https://sagold.com/remote')
Note the support for $ref resolution has additional complexities, if you add nested $ids to you schema. Here, json-schema-library has only partial support (@see integration test result). Thus, it is recommended to omit the features of changing scopes by nested $ids. For more details, see json-schema.org: Structuring a complex schema
Access local subschemas in remote schemas
You can add a local uri reference to the remote schema by using the # separator. The following example resolves hte local path /$defs/character in the remote schema https://sagold.com/remote throught the combined url:https://sagold.com/remote#/$defs/character
`ts
jsonSchema.addRemoteSchema('https://sagold.com/remote', {
$defs: {
character: {
title: 'A character',
type: 'string',
minLength: 1,
maxLength: 1
}
}
})
jsonSchema.setSchema({
$id: 'https://sagold.com/local',
$ref: 'https://sagold.com/remote#/$defs/character'
})
jsonSchema.validate('AB') // maxLength error
jsonSchema.getTemplate('A') // "A" - default value resolved
// returns remote schema (from compiled local schema):
jsonSchema.getSchema().getRef('https://sagold.com/remote#/$defs/character')
`
Note json-pointers are not restricted to $defs (definitions), but can reference any subschema. For example:
`ts
jsonSchema.addRemoteSchema('https://sagold.com/remote', {
type: 'object',
properties: {
character: {
title: 'A character',
type: 'string',
minLength: 1,
maxLength: 1
}
}
})
jsonSchema.setSchema({
$id: 'https://sagold.com/local',
$ref: 'https://sagold.com/remote#/properties/character'
})
jsonSchema.validate('AB') // maxLength error
jsonSchema.getTemplate('A') // "A" - default value resolved
// returns remote schema (from compiled local schema):
jsonSchema.getSchema().getRef('https://sagold.com/remote#/properties/character')
`
createSchemaOf returns a simple json-schema of the input data.
`ts`
const jsonSchema = new Draft07(mySchema)
const schema: JsonSchema = jsonSchema.createSchemaOf({ title: 'initial value' })
compileSchema adds _$ref_ resolution support to a json-schema. Internally, each draft compiles a passed schema on its own, but when passing additional schemas to individual functions, compileSchema has to be called manually for json-schemas containing _$ref_-references.
`ts`
const jsonSchema = new Draft07(mySchema)
const compiledSchema = jsonSchema.compileSchema({ $ref: '/$defs/table' })
const tableSchema = compiledSchema.getRef()
Note that draft.compileSchema compiles a schema under the current rootSchema. That is, definitions from root schema will be copied to the local schema, to enable _$ref_ resolutions.
For each draft json-schema-library supports the following custom properties:
For error generation, an attribute patternExample may be set for a pattern validation. Instead of the regular
expression, the example will be printed in the error message.
For oneOf resolution, json-schema states that data is valid if it validates against exactly one of those sub-schemas. In some scenarios this is unwanted behaviour, as the actual oneOf schema is known and only validation errors of this exact sub-schema should be returned.
For an explicit oneOf resolution, the json-schema may be extended by a property oneOfProperty. This will always associate an entry with a matching value (instead of schema validation) and return only this schema or validation errors, depending on the current task. For example:
`ts
const schema = {
oneOfProperty: 'id',
oneOf: [
{
type: 'object',
properties: { id: { const: '1' }, title: { type: 'number' } }
},
{
type: 'object',
properties: { id: { const: '2' }, title: { type: 'number' } }
},
{
type: 'object',
properties: { id: { const: '3' }, title: { type: 'number' } }
}
]
}
const resolvedSchema = jsonSchema.resolveOneOf({ id: '2', title: 'not a number' }, schema)
// will always return (even if invalid)
expect(resolvedSchema).to.deep.eq({
type: 'object',
properties: { id: { const: '2' }, title: { type: 'number' } }
})
`
getTemplate default options | custom resolvers | custom validators | custom errors
Each Draft in json-schema-library is build around a DraftConfig. A DraftConfig holds all _functions_ and _configurations_ for each json-schema drafts. The DraftConfig is your main way to alter or extend behaviour for json-schema-library. You can either create your own _draftConfig_ or adjust any existing _draftConfig_. For the current drafts (4-7), each _draftConfig_ is exposed along with its actual _class_. For example:
`ts
import { Draft, Draft07, draft07Config } from 'json-schema-library'
// the following calls are identical:
new Draft(draft07Config, mySchema)
new Draft07(mySchema, draft07Config)
new Draft07(mySchema, {})
new Draft07(mySchema)
`
All draft configurations for specific Draft classes accept a partial configuration that lets you overwrite default behaviour:
> replace the strict resolveOneOf behaviour to use fuzzy search instead:
`ts
import { Draft07, draft07Config, resolveOneOfFuzzy } from 'json-schema-library'
// the following calls are identical:
new Draft07(mySchema, { resolveOneOf: resolveOneOfFuzzy })
new Draft({ ...draft07Config, resolveOneOf: resolveOneOfFuzzy }, mySchema)
`
With version 8 _json-schema-library_ has changed getTemplate to only add required properties per default. This can be changed on draft initialization, by passing templateDefaultOptions in the _draftConfig_:
`ts`
const draft = new Draft(schema, {
templateDefaultOptions: {
addOptionalProps: true
}
})
Note You can still pass options to getTemplate overriding the draft default settings by:
`ts`
const data = draft.getTemplate({}, draft.getSchema(), {
addOptionalProps: true
})
A _resolver_ is a simple method implementing a specific feature of json-schema to retrieve a sub-schema. Implementing the signature of each resolver you can create and pass your own resolvers.
#### resolveRef with merge
The default json-schema behaviour for $ref resolution is to replace the schema where a $ref is defined. In some scenarios you what to add context-specific information (e.g., a specific _title_). For this, a modified $ref-resolver is exposed by json-schema-library:
`ts
import { Draft07, draft07Config, resolveRefMerge } from 'json-schema-library'
const jsonSchema = new Draft07(mySchema, { resolveRef: resolveRefMerge })
`
resolveRefMerge performs a shallow merge (first level of properties), adding the local schemas properties last.
Caution: With this resolver, it is possible to overwrite json-schema behavioural properties. Treat with care.
Example
`ts
import { Draft07, draft07Config, resolveRefMerge } from 'json-schema-library'
const mySchema = {
type: 'object',
properties: {
subHeader: {
$ref: '#/$defs/header',
title: 'sub header'
}
},
$defs: {
header: {
title: 'header',
type: 'string'
}
}
}
const jsonSchema = new Draft07(mySchema, { resolveRef: resolveRefMerge })
const subHeaderSchema = jsonSchema.getSchema('#/subHeader')
expect(subHeaderSchema).to.eq({
title: 'sub header',
type: 'string'
})
`
#### resolveOneOf fuzzy search
The default json-schema behaviour for oneOf resolution is to validate all contained _oneOf_-schemas and return the one schema that validates against the given input data. If no item validates completely an error returned, containing all validation errors of all schemas. When you are interested in the actual error (rather than simply determining βIs the data is valid or not?β), this is behaviour is not very helpful as the result is hard to read.
json-schema-library exposes a method resolveOneOfFuzzy, which will return a single schema in cases where no valid schema could be resolved. resolveOneOfFuzzy uses a simple scoring mechanism to return the best fitting schema for the given input data. Thus, resolveOneOfFuzzy may return schemas that do not validate a given input data.
`ts
import { Draft07, draft07Config, resolveOneOfFuzzy } from 'json-schema-library'
const jsonSchema = new Draft07(mySchema, { resolveOneOf: resolveOneOfFuzzy })
`
All json-schema validation is done using validator functions for _keywords_ and _formats_.
keyword validators are called for each keyword defined on a json-schema. For example, the following schema will run two keyword-validators (one for items and one of minItems) which are defined in draft.validateKeyword.items and draft.validateKeyword.minItems.
`ts`
{ type: "object", items: {}, minItems: 1 }
Since valid json-schema keywords vary by their type an additional mapping registers, which keyword should be tested per schema-type. This mapping is defined in draft.typeKeywords:
`ts
import { draft07Config } from 'json-schema-library'
console.log(draft07Config.typeKeywords.array)
// ["enum", "contains", "items", "minItems", "maxItems", "uniqueItems", "not", "if"];
`
> The keyword format is also registered in draft.validateKeyword.format, but each actual format validation is defined as follows:
format validators are called on each occurrence of a property format in a json-schema. In the next example, the schema will run the _email_-validator given in draft.validateFormat.email:
`ts`
{ type: "string", format: "email" }
#### add custom keyword validator
To add or overwrite a keyword validator, you must add a validator function on your draft config in validateKeyword.
Using specific Draft configuration, where draft configuration objects will be merged:
`ts
import { Draft07, JsonValidator } from 'json-schema-library'
const jsonSchema = new Draft07(mySchema, {
validateKeyword: {
customKeyword: myCustomKeywordValidator as JsonValidator
},
// in case for new keywords, or if keyword should be supported on other types
// add keyword-name to typeKeywords
typeKeywords: {
object: draft07Config.typeKeywords.object.concat('customKeyword')
}
})
`
Example: Manually extending draft configuration:
`ts
import { Draft, JsonValidator, draft07Config } from 'json-schema-library'
const myDraftConfiguration = {
...draft07Config,
draft07Config,
validateKeyword: {
...draft07Config.validateKeyword,
customKeyword: myCustomKeywordValidator as JsonValidator
},
// in case for new keywords, or if keyword should be supported on other types
// add keyword-name to typeKeywords
typeKeywords: {
...draft07Config.typeKeywords,
object: draft07Config.typeKeywords.object.concat('customKeyword')
}
}
const jsonSchema = new Draft(myDraftConfiguration, mySchema)
`
#### add custom format validator
To add or overwrite a format validator you must add a validator function on your draft config in validateFormat.
`ts
import { Draft07, JsonValidator } from 'json-schema-library'
const jsonSchema = new Draft07(mySchema, {
validateFormat: {
customFormat: myCustomFormatValidator as JsonValidator
}
})
`
json-schema-library exposes available errors on its draft configurations on DraftConfig.errors and uses a global configuration config.strings for error messages. Both can be extended or modified.
`ts
import { config, createCustomError, draft07Config } from 'json-schema-library'
draft07Config.errors.enumError
// (data: { pointer: JsonPointer } & Record
console.log(config.strings.EnumError)
// "Expected given value {{value}} in {{pointer}} to be one of {{values}}"`
Each error message in config.strings receives the data-property of an error. These properties can be referenced in handlebars brackets and will be replaced automatically. To demonstrate the behaviour:
`ts
import { render } from 'json-schema-library'
render('Expected given value {{value}} in {{pointer}} to be one of {{values}}', {[B]
pointer: '[A]',
value: '[B]'
})
// "Expected given value in [A] to be one of "`
#### customize error messages
`ts
import { config } from 'json-schema-library'
config.strings.EnumError = 'Invalid enum value {{value}} in {{pointer}}'
``
#### customize errors
`ts
import { ErrorData, JsonError, draft07Config } from 'json-schema-library'
draft07Config.errors.EnumError = (data: ErrorData): JsonError => {
return {
type: 'error',
code: 'my-error',
name: 'MyError',
message: something went wrong at ${data.pointer},`
data
}
}
#### create errors
`ts
import { createError, draft07Config } from 'json-schema-library'
// will use the string from config.strings.EnumError as message``
const error: JsonError = createError('EnumError', { data: { pointer: '#/location' } })