# Schema
Nullable Values
The OpenAPI specification v2 does not allow for nullable values in schemas, but to accommodate for that need a property x-nullable
can be defined on any schema to allow the null
value.
# Instance Methods
# deserialize
Schema.prototype.deserialize ( value [, options ] ) : EnforcerResult < any >
Schema instances can deserialize values. Deserialization is the process of extracting a data structure from a scalar value. For example, the string 2000-01-01
as a date string would be deserialized to new Date('2000-01-01')
which gives you a date object instead of a date string.
Note that the deserialization process keeps validation to a minimum. It won't care if a decimal number was provided for an integer
type, but it will care if "hello"
is provided as an integer
.
Parameters:
Parameter | Description | Type | Default |
---|---|---|---|
value | The value to deserialize | any | |
options | Deserialization options. See the options table below for details. | object |
Deserialization Options
Option | Description | Type | Default |
---|---|---|---|
strict | Whether to enable strict deserialization. Setting to false will allow strings to deserialize for booleans, integers, and numbers. It will also allow booleans to deserialize from numbers. Keeping true will reduce false positives. | boolean | true |
Returns: An EnforcerResult that resolves to the deserialized value.
Example
const Enforcer = require('openapi-enforcer')
const [ schema ] = new Enforcer.v3_0.Schema({ type: 'string', format: 'date-time' })
const [ value ] = schema.deserialize('2000-01-01T00:00:00.000Z')
console.log(value instanceof Date) // true
console.log(value.getFullYear()) // 2000
# discriminate
Schema.prototype.discriminate ( value [, details ]) : object
Schemas that use discriminators allow polymorphism or schema selection functionality. This function is used to get the Schema instance that is referenced through the discriminator.
Parameters:
Parameter | Description | Type | Default |
---|---|---|---|
value | The object containing the discriminator property | object | |
details | Whether to get back just the Schema instance (false ) or the Schema instance, property name, and property value (true ). | boolean | false |
Returns: The discriminator Schema instance if details=false
, or and object with the properties key
(discriminator property name), name
(value property name), and schema
(the Schema instance) if details=true
.
Example
const Enforcer = require('openapi-enforcer')
const definition = {
swagger: '2.0',
info: { title: '', version: '' },
paths: {},
definitions: {
Cat: {
allOf: [
{ '$ref': '#/definitions/Pet' },
{
type: 'object',
properties: {
birthDate: { type: 'string' },
huntingSkill: { type: 'string' },
}
}
]
},
Dog: {
allOf: [
{ '$ref': '#/definitions/Pet' },
{
type: 'object',
properties: {
birthDate: { type: 'string', format: 'date' },
packSize: { type: 'integer', minimum: 1 }
}
}
]
},
Pet: {
type: 'object',
required: ['petType'],
properties: {
petType: { type: 'string' }
},
discriminator: 'petType'
}
}
}
Enforcer(definition)
.then(enforcer => {
const schema = enforcer.definitions.Pet
const dogSchema = schema.discriminate({ petType: 'Dog' })
console.log(dogSchema === enforcer.definitions.Dog) // true
})
# formalize
Schema.prototype.formalize ( value ) : any
This is a convenience function that calls the static Schema.formalize function. Please see the documentation for Schema.formalize for usage and examples.
# populate
Schema.prototype.populate ([ params [, value [, options ] ] ]) : EnforcerResult < any >
This method is used to generate values using a combination of a parameters map and the schema definition.
Parameters:
Parameter | Description | Type | Default |
---|---|---|---|
params | An object map, tying key value pairs to locations in the schema definition. | object | {} |
value | An initial value to start with. Properties already defined in this value will not be overwritten during population. | any | |
options | Options to apply during population. See below. | object |
Options Parameter
Property | Description | Type | Default |
---|---|---|---|
copy | Whether to copy the initial value (true ) or mutate the initial value (false ). | boolean | false |
conditions | Whether to check that the condition (x-condition ) is met prior to population for a value. | boolean | true |
defaults | Whether to apply default value (x-default then default ) if no other value is specified. | boolean | true |
depth | How deep to traverse an object that is being built. | number | 100 |
replacement | The template replacement method to use. Options include colon (:name ), doubleHandlerBar ( ), or handlebar ({name} ). | string | 'handlebar' |
templateDefaults | Whether to apply template replacement to default values. | boolean | true |
templates | Whether to use templating (x-template ) to populate the value. | boolean | true |
variables | Whether to use variables (x-variable ) to populate the value. | boolean | true |
Returns: An EnforcerResult that resolves to the populated value.
Example
const Enforcer = require('openapi-enforcer')
const [ schema ] = new Enforcer.v3_0.Schema({
type: 'object',
properties: {
age: {
type: 'integer',
'x-variable': 'age',
'x-condition': 'above18'
},
firstName: {
type: 'string',
'x-variable': 'first'
},
fullName: {
type: 'string',
default: '{first} {last}'
},
lastName: {
type: 'string',
'x-variable': 'last'
}
}
})
const [ adult ] = schema.populate({
above18: true,
age: 25,
first: 'Bob',
last: 'Johnson'
})
const [ child ] = schema.populate({
above18: false,
age: 6,
first: 'Tim',
last: 'Turner'
})
console.log(adult)
// {
// age: 25,
// firstName: 'Bob',
// fullName: 'Bob Johnson',
// lastName: 'Johnson'
// }
console.log(child)
// {
// firstName: 'Tim',
// fullName: 'Tim Turner',
// lastName: 'Turner'
// }
# random
Schema.prototype.random ([ value [, options ] ]) : EnforcerResult < any >
Generate a random value that complies with the schema definition.
Parameters:
Parameter | Description | Type | Default |
---|---|---|---|
value | An initial value to use to begin adding randomly generated values to. | any | |
options | Configuration options. See below. | object |
Options Parameter
Property | Description | Type | Default |
---|---|---|---|
additionalPropertiesPossibility | A number between 0 and 1 that signifies the possibility of additional properties being added to objects that allow them. In cases where the definition's minProperties has not been reached or if a property is required but not defined as a known property then that additional property will be added, regardless of the additionalPropertiesPossibility value. | number | 0 |
arrayVariation | The maximum random array size. This value may be overwritten if the schema defines minItems or maxItems that do not fit this value. | number | 4 |
copy | Whether the passed in value should be copied (true ) or mutated (false ). | boolean | false |
defaultPossibility | A number between 0 and 1 that signifies the possibility of a default value being used when one exists. | number | 0.25 |
definedPropertyPossibility | A number between 0 and 1 that signifies the possibility of setting a value for an object with a defined property. If the property is required then the random value will be set regardless of the defaultPossibility value. | number | 0.80 |
maxDepth | Maximum depth to build to for a random object or array. | number | 10 |
numberVariation | The amount of variation to have between high and low numbers. This value will be overwritten if minimum and maximum are defined for the schema. | number | 1000 |
uniqueItemRetry | The number of times to attempt to come up with a unique value for arrays that have uniqueItems set to true . | number | 5 |
Returns: An EnforcerResult that resolves to the random value.
Example
const Enforcer = require('openapi-enforcer')
const [ schema ] = new Enforcer.v3_0.Schema({
type: 'number',
minimum: 0,
multipleOf: 0.5
})
const [ value ] = schema.random()
console.log(value) // 1.5
# serialize
Schema.prototype.serialize ( value ) : EnforcerResult < any >
Serialization is the process of converting a data structure to a scalar value. For example, the date object new Date('2000-01-01')
would be serialized to the string 2000-01-01
if the type=string
and format=date
.
Parameters:
Parameter | Description | Type | Default |
---|---|---|---|
value | The value to serialize. | any |
Returns: An EnforcerResult that resolves to the serialized value.
Example
const Enforcer = require('openapi-enforcer')
const [ schema ] = new Enforcer.v3_0.Schema({ type: 'string', format: 'date' })
const [ value ] = schema.serialize(new Date('2000-01-01T00:00:00.000Z'))
console.log(value) // '2000-01-01'
# validate
Schema.prototype.validate ( value [, options ] ) : EnforcerException | undefined
Validate a deserialized value against the schema.
Parameters:
Parameter | Description | Type | Default |
---|---|---|---|
value | The deserialized value to validate. | any | |
options | Configuration options. See below. | object |
Options Parameter
Property | Description | Type | Default |
---|---|---|---|
readWriteMode | If this value is set to read then any properties in the value that are listed as writeOnly: true will produce an error. If the value is set to "write" then any properties in the value listed as readOnly: true will produce an error. | string | undefined |
Returns: An EnforcerException object an the value is not valid, otherwise undefined
.
Example
const Enforcer = require('openapi-enforcer')
const [ schema ] = new Enforcer.v3_0.Schema({ type: 'string' })
const err = schema.validate(123)
console.log(err)
// Invalid value
// Expected a string. Received: 123
{% import to-object.md %}
# Static Methods
# defineDataTypeFormat
Schema.defineDataTypeFormat ( type, format, configuration ) : undefined
This is a static method that is used to define custom data formats, their serialization and deserialization, and their validation. If you have custom object classes that need special serialization, deserialization, and validation then this method is where you can define that.
Built into the system already is support for type 'string'
for formats 'binary'
, 'byte'
, 'date'
, and 'date-time'
.
Parameters:
Parameter | Description | Type | Default |
---|---|---|---|
type | The type that this data format definition will apply to. This is directly tied to the OpenAPI document schemas type property, therefore this value must be one of 'boolean' , 'integer' , 'number' , or 'string' as defined in the OpenAPI specification. | string | |
format | The name of the format that this type definition will apply to. | string | |
configuration | The configuration instructions for this type and format. See below. | object |
Configuration Parameter
Property | Description | Type | Default |
---|---|---|---|
constructors | An array of functions to be recognized as constructors. | Array < function > | |
deserialize | The function to call to deserialize the value. It receives one parameter, an object, with properties exception , schema , and value which contains the serialized value. This function should return the deserialized value. | function | |
isNumeric | If this value is numeric then it allows the schema properties maximum , minimum , exclusiveMaximum , exclusiveMinimum , and multipleOf . Defaults to true if the type is integer or number , otherwise false . | boolean | See description |
random | The function to call to generate a random deserialized value. It receives one parameter, an object, with properties exception and schema . The function should return the deserialized value. | function | |
serialize | The function to call to serialize the value. It receives one parameter, an object, with properties exception , schema , and value which contains the deserialized value. This function should return the serialized value. | function | |
validate | The function to call to validate the deserialized value. It receives one parameter, and object, with the properties exception , schema , and value which contains the deserialized value. This function does not need to return anything and can report errors via the exception object. | function |
Returns: undefined
.
Example
This example shows how you might define a decimal type that uses exact decimal values (instead of floating point). The example omits many validations and scenarios for simplicity sake.
// define the Decimal class
class Decimal {
constructor (value) {
const array = value.split('.')
this.characteristic = array[0]
this.mantissa = array[1] || '0'
}
valueOf () {
return +this.characteristic + +this.mantissa / Math.pow(10, this.mantissa.length)
}
toString () {
return this.characteristic + '.' + this.mantissa
}
}
// define a "decimal" format
const Schema = require('openapi-enforcer').v3_0.Schema
Schema.defineDataTypeFormat('string', 'decimal', {
constructors: [ Decimal ],
// define how to deserialize a value
deserialize: (exception, value) => new Decimal(value),
// is numeric - allows schema maximum, minimum, exclusiveMaximum, etc.
isNumeric: true,
// generate a random value
random: (exception) => new Decimal(String(Math.random() * 100)),
// define how to serialize a value
serialize: (exception, value) => value.toString(),
// define validation function for deserialized value
validate: (exception, value) => {
if (this.hasOwnProperty('minimum') && this.minimum > +value) {
exception.message('Value must be above the minimum of ' +
this.minimum + '. Received: ' + value)
}
}
})
// create a schema that uses the "decimal" format
const [ schema ] = new Schema({ type: 'string', format: 'decimal' })
// deserialize a "decimal"
const [ value ] = schema.deserialize('2.49')
console.log(value instanceof Decimal) // true
console.log(+value) // 2.49
# extractValue
Schema.extractValue ( value )
This is an alias for the Schema.Value.extract
function.
# formalize
Schema.formalize ( value ) : any
A schema instance's serialize and validate functions require that objects meet one of two criteria:
- Objects must be plain objects, or
- Objects must have a defined schema data type that defines serialization and validation.
To this end, formalize
will correctly convert your non plain objects to a format that can be used by the serialize and validate functions. In other words, this function will convert a non plain object to either a plain object equivalent or it maintain the defined type.
Parameters:
Parameter | Description | Type | Default |
---|---|---|---|
value | The value to formalize | any |
Returns a formalized value.
Example
function Person (name, birthdate) {
this.name = name;
this.birthdate = birthdate;
}
const person = new Person('bob', new Date('2000-01-01T00:00:00.000Z'))
const plainObject = Enforcer.v3_0.formalize(person)
# hook
Schema.hook ( type, handler ) : void
Add a hook to schema deserialize, serialize, and validate functonality.
Parameters:
Parameter | Description |
---|---|
type | The type of hook to add. Expects on of the following values: "afterDeserialize" , "afterSerialize" , "afterValidate" , "beforeDeserialize" , "beforeSerialize" , or "beforeValidate" |
handler | The function to call for the hook. Every hook function must run synchronously, receives the parameters value , schema , and exception , and should return an object with the following structure: { done: false, hasException: false, value: 'whatever' } . The hasException property is optional and allows for performance optimization. If your hook adds an exception then set the value to true , otherwise return it as false . |
In the case that an exception exists your hook function will not be run. It's possible another hook may run and specify that the process is done: true
, also, preventing your hook from running.
Returns undefined
Example
// define a custom beforeDeserialize hook
function zeroDateHook (value, schema, exception) {
if (schema.type === 'string' && schema.format === 'date' && value === '0000-00-00') {
// custom deserialize functionality example
return {
done: true, // if done then don't allow any other deserialize functions to run, we are done
hasException: false, // we didn't add any exception messages with this hook
value: new Date(0)
}
} else if (schema.type === 'string' && schema.format === 'date-time' && value === '0000-00-00') {
// exception example
exception.message('Zero dates are not allowed for date-time formats.')
return {
done: true,
hasException: true,
value
}
} else {
// no changes example
// we didn't make any changes so pass along the unchanged value and let other deserializers work on it
return {
done: false,
hasException: false,
value
}
}
}
Enforcer.v2_0.Schema.hook('beforeDeserialize', hook)
Enforcer.v3_0.Schema.hook('beforeDeserialize', hook)
# unhook
Schema.unhook ( type, handler ) : void
Remove a previously added hook.
Parameters:
Parameter | Description |
---|---|
type | The type of hook to remove. Expects on of the following values: "afterDeserialize" , "afterSerialize" , "afterValidate" , "beforeDeserialize" , "beforeSerialize" , or "beforeValidate" |
handler | The function to unhook. |
Returns undefined
Example
function myHook (value, schema, exception) { ... }
// add the hook
Enforcer.v2_0.Schema.hook('beforeDeserialize', myHook)
Enforcer.v3_0.Schema.hook('beforeDeserialize', myHook)
// remove the hook
Enforcer.v2_0.Schema.unhook('beforeDeserialize', myHook)
Enforcer.v3_0.Schema.unhook('beforeDeserialize', myHook)
# Value
Schema.value ( value, options ) : any
This is a sub class used only by the Schema and is used to provide more fine grained control over what parts of a value serialize, deserialize, validate, and populate.