npm.io
7.0.1 • Published 1 week ago

fast-json-stringify

Licence
MIT
Version
7.0.1
Deps
6
Size
396 kB
Vulns
0
Weekly
0
Stars
3.7K

fast-json-stringify

CI NPM version neostandard javascript style NPM downloads

fast-json-stringify is significantly faster than JSON.stringify() for small payloads. Its performance advantage shrinks as your payload grows.

How it works

fast-json-stringify requires a JSON Schema Draft 7 input to generate a fast stringify function.

Benchmarks

  • Machine: EX41S-SSD, Intel Core i7, 4Ghz, 64GB RAM, 4C/8T, SSD.
  • Node.js v22.14.0
FJS creation x 9,696 ops/sec ±0.77% (94 runs sampled)
CJS creation x 197,267 ops/sec ±0.22% (95 runs sampled)
AJV Serialize creation x 48,302,927 ops/sec ±2.09% (90 runs sampled)
json-accelerator creation x 668,430 ops/sec ±0.43% (95 runs sampled)
JSON.stringify array x 7,924 ops/sec ±0.11% (98 runs sampled)
fast-json-stringify array default x 7,183 ops/sec ±0.09% (97 runs sampled)
json-accelerator array x 5,762 ops/sec ±0.27% (99 runs sampled)
fast-json-stringify array json-stringify x 7,171 ops/sec ±0.17% (97 runs sampled)
compile-json-stringify array x 6,889 ops/sec ±0.41% (96 runs sampled)
AJV Serialize array x 6,945 ops/sec ±0.17% (98 runs sampled)
JSON.stringify large array x 331 ops/sec ±0.17% (93 runs sampled)
fast-json-stringify large array default x 208 ops/sec ±0.21% (91 runs sampled)
fast-json-stringify large array json-stringify x 330 ops/sec ±0.17% (93 runs sampled)
compile-json-stringify large array x 318 ops/sec ±0.11% (90 runs sampled)
AJV Serialize large array x 114 ops/sec ±0.27% (74 runs sampled)
JSON.stringify long string x 13,452 ops/sec ±0.15% (99 runs sampled)
fast-json-stringify long string x 13,454 ops/sec ±0.10% (99 runs sampled)
json-accelerator long string x 13,439 ops/sec ±0.09% (98 runs sampled)
compile-json-stringify long string x 13,380 ops/sec ±0.12% (100 runs sampled)
AJV Serialize long string x 21,932 ops/sec ±0.06% (99 runs sampled)
JSON.stringify short string x 12,114,052 ops/sec ±0.59% (97 runs sampled)
fast-json-stringify short string x 29,408,175 ops/sec ±1.12% (91 runs sampled)
json-accelerator short string x 29,431,694 ops/sec ±1.05% (93 runs sampled)
compile-json-stringify short string x 24,740,338 ops/sec ±1.02% (91 runs sampled)
AJV Serialize short string x 17,841,869 ops/sec ±0.90% (91 runs sampled)
JSON.stringify obj x 4,577,494 ops/sec ±0.25% (94 runs sampled)
fast-json-stringify obj x 7,291,157 ops/sec ±0.40% (97 runs sampled)
json-accelerator obj x 6,473,194 ops/sec ±0.31% (99 runs sampled)
compile-json-stringify obj x 14,724,935 ops/sec ±0.50% (96 runs sampled)
AJV Serialize obj x 8,782,944 ops/sec ±0.45% (93 runs sampled)
JSON stringify date x 803,522 ops/sec ±0.47% (98 runs sampled)
fast-json-stringify date format x 1,117,776 ops/sec ±0.69% (95 runs sampled)
json-accelerate date format x 1,122,419 ops/sec ±0.20% (97 runs sampled)
compile-json-stringify date format x 803,214 ops/sec ±0.23% (97 runs sampled)
Table of contents:

Example

const fastJson = require('fast-json-stringify')
const stringify = fastJson({
  title: 'Example Schema',
  type: 'object',
  properties: {
    firstName: {
      type: 'string'
    },
    lastName: {
      type: 'string'
    },
    age: {
      description: 'Age in years',
      type: 'integer'
    },
    reg: {
      type: 'string'
    }
  }
})

console.log(stringify({
  firstName: 'Matteo',
  lastName: 'Collina',
  age: 32,
  reg: /"([^"]|\\")*"/
}))

Options

Optionally, you may provide to fast-json-stringify an option object as the second parameter:

const fastJson = require('fast-json-stringify')
const stringify = fastJson(mySchema, {
  schema: { ... },
  ajv: { ... },
  rounding: 'ceil'
})

API

fastJsonStringify(schema)

Build a stringify() function based on jsonschema draft 7 spec.

Supported types:

  • 'string'
  • 'integer'
  • 'number'
  • 'array'
  • 'object'
  • 'boolean'
  • 'null'

And nested ones, too.

Specific use cases
Instance Serialized as
Date string via toISOString()
RegExp string
BigInt integer via toString

JSON Schema built-in formats for dates are supported and will be serialized as:

Format Serialized format example
date-time 2020-04-03T09:11:08.615Z
date 2020-04-03
time 09:11:08

Note: In the case of a string formatted Date and not Date Object, there will be no manipulation on it. It should be properly formatted.

Example with a Date object:

const stringify = fastJson({
  title: 'Example Schema with string date-time field',
  type: 'string',
  format: 'date-time'
})

const date = new Date()
console.log(stringify(date)) // '"YYYY-MM-DDTHH:mm:ss.sssZ"'

Required

You can set specific fields of an object as required in your schema by adding the field name inside the required array in your schema. Example:

const schema = {
  title: 'Example Schema with required field',
  type: 'object',
  properties: {
    nickname: {
      type: 'string'
    },
    mail: {
      type: 'string'
    }
  },
  required: ['mail']
}

If the object to stringify is missing the required field(s), fast-json-stringify will throw an error.

Missing fields

If a field is present in the schema (and is not required) but it is not present in the object to stringify, fast-json-stringify will not write it in the final string. Example:

const stringify = fastJson({
  title: 'Example Schema',
  type: 'object',
  properties: {
    nickname: {
      type: 'string'
    },
    mail: {
      type: 'string'
    }
  }
})

const obj = {
  mail: 'mail@example.com'
}

console.log(stringify(obj)) // '{"mail":"mail@example.com"}'

Defaults

fast-json-stringify supports default jsonschema key in order to serialize a value if it is undefined or not present.

Example:

const stringify = fastJson({
  title: 'Example Schema',
  type: 'object',
  properties: {
    nickname: {
      type: 'string',
      default: 'the default string'
    }
  }
})

console.log(stringify({})) // '{"nickname":"the default string"}'
console.log(stringify({nickname: 'my-nickname'})) // '{"nickname":"my-nickname"}'

Pattern properties

fast-json-stringify supports pattern properties as defined by JSON schema. patternProperties must be an object, where the key is a valid regex and the value is an object, declared in this way: { type: 'type' }. patternProperties will work only for the properties that are not explicitly listed in the properties object. Example:

const stringify = fastJson({
  title: 'Example Schema',
  type: 'object',
  properties: {
    nickname: {
      type: 'string'
    }
  },
  patternProperties: {
    'num': {
      type: 'number'
    },
    '.*foo

Additional properties

fast-json-stringify supports additional properties as defined by JSON schema. additionalProperties must be an object or a boolean, declared in this way: { type: 'type' }. additionalProperties will work only for the properties that are not explicitly listed in the properties and patternProperties objects.

If additionalProperties is not present or is set to false, every property that is not explicitly listed in the properties and patternProperties objects will be ignored, as described in Missing fields. Missing fields are ignored to avoid having to rewrite objects before serializing. However, other schema rules would throw in similar situations. If additionalProperties is set to true, it will be used by JSON.stringify to stringify the additional properties. If you want to achieve maximum performance, we strongly encourage you to use a fixed schema where possible. The additional properties will always be serialized at the end of the object. Example:

const stringify = fastJson({
  title: 'Example Schema',
  type: 'object',
  properties: {
    nickname: {
      type: 'string'
    }
  },
  patternProperties: {
    'num': {
      type: 'number'
    },
    '.*foo
AnyOf and OneOf

fast-json-stringify supports the anyOf and oneOf keywords as defined by JSON schema. Both must be an array of valid JSON schemas. The different schemas will be tested in the specified order. The more schemas stringify has to try before finding a match, the slower it will be.

anyOf and oneOf use ajv as a JSON schema validator to find the schema that matches the data. This has an impact on performance—only use it as a last resort.

Example:

const stringify = fastJson({
  title: 'Example Schema',
  type: 'object',
  properties: {
    'undecidedType': {
      'anyOf': [{
        type: 'string'
      }, {
        type: 'boolean'
      }]
    }
  }
})

When specifying object JSON schemas for anyOf, add required validation keyword to match only the objects with the properties you want.

Example:

const stringify = fastJson({
  title: 'Example Schema',
  type: 'array',
  items: {
    anyOf: [
      {
        type: 'object',
        properties: {
          savedId: { type: 'string' }
        },
        // without "required" validation any object will match
        required: ['savedId']
      },
      {
        type: 'object',
        properties: {
          error: { type: 'string' }
        },
        required: ['error']
      }
    ]
  }
})

If/then/else

fast-json-stringify supports if/then/else jsonschema feature. See ajv documentation.

Example:

const stringify = fastJson({
  'type': 'object',
  'properties': {
  },
  'if': {
    'properties': {
      'kind': { 'type': 'string', 'enum': ['foobar'] }
    }
  },
  'then': {
    'properties': {
      'kind': { 'type': 'string', 'enum': ['foobar'] },
      'foo': { 'type': 'string' },
      'bar': { 'type': 'number' }
    }
  },
  'else': {
    'properties': {
      'kind': { 'type': 'string', 'enum': ['greeting'] },
      'hi': { 'type': 'string' },
      'hello': { 'type': 'number' }
    }
  }
})

console.log(stringify({
  kind: 'greeting',
  foo: 'FOO',
  bar: 42,
  hi: 'HI',
  hello: 45
})) // {"kind":"greeting","hi":"HI","hello":45}
console.log(stringify({
  kind: 'foobar',
  foo: 'FOO',
  bar: 42,
  hi: 'HI',
  hello: 45
})) // {"kind":"foobar","foo":"FOO","bar":42}

NB Do not declare the properties twice or you will print them twice!

Reuse - $ref

If you want to reuse a definition of a value, you can use the property $ref. The value of $ref must be a string in JSON Pointer format. Example:

const schema = {
  title: 'Example Schema',
  definitions: {
    num: {
      type: 'object',
      properties: {
        int: {
          type: 'integer'
        }
      }
    },
    str: {
      type: 'string'
    }
  },
  type: 'object',
  properties: {
    nickname: {
      $ref: '#/definitions/str'
    }
  },
  patternProperties: {
    'num': {
      $ref: '#/definitions/num'
    }
  },
  additionalProperties: {
    $ref: '#/definitions/def'
  }
}

const stringify = fastJson(schema)

If you need to use an external definition, you can pass it as an option to fast-json-stringify. Example:

const schema = {
  title: 'Example Schema',
  type: 'object',
  properties: {
    nickname: {
      $ref: 'strings#/definitions/str'
    }
  },
  patternProperties: {
    'num': {
      $ref: 'numbers#/definitions/num'
    }
  },
  additionalProperties: {
    $ref: 'strings#/definitions/def'
  }
}

const externalSchema = {
  numbers: {
    definitions: {
      num: {
        type: 'object',
        properties: {
          int: {
            type: 'integer'
          }
        }
      }
    }
  },
  strings: require('./string-def.json')
}

const stringify = fastJson(schema, { schema: externalSchema })

External definitions can also reference each other. Example:

const schema = {
  title: 'Example Schema',
  type: 'object',
  properties: {
    foo: {
      $ref: 'strings#/definitions/foo'
    }
  }
}

const externalSchema = {
  strings: {
    definitions: {
      foo: {
        $ref: 'things#/definitions/foo'
      }
    }
  },
  things: {
    definitions: {
      foo: {
        type: 'string'
      }
    }
  }
}

const stringify = fastJson(schema, { schema: externalSchema })

Long integers

By default, the library will handle automatically BigInt.

Integers

The type: integer property will be truncated if a floating point is provided. You can customize this behavior with the rounding option that will accept round, ceil, floor, or trunc. Default is trunc:

const stringify = fastJson(schema, { rounding: 'ceil' })

Nullable

According to the Open API 3.0 specification, a value that can be null must be declared nullable.

Nullable object
const stringify = fastJson({
  'title': 'Nullable schema',
  'type': 'object',
  'nullable': true,
  'properties': {
    'product': {
      'nullable': true,
      'type': 'object',
      'properties': {
        'name': {
          'type': 'string'
        }
      }
    }
  }
})

console.log(stringify({product: {name: "hello"}})) // "{"product":{"name":"hello"}}"
console.log(stringify({product: null})) // "{"product":null}"
console.log(stringify(null)) // null

Otherwise, instead of raising an error, null values will be coerced as follows:

  • integer -> 0
  • number -> 0
  • string -> ""
  • boolean -> false
  • object -> {}
  • array -> []

Large Arrays

Large arrays are, for the scope of this document, defined as arrays containing, by default, 20000 elements or more. That value can be adjusted via the option parameter largeArraySize.

At some point the overhead caused by the default mechanism used by fast-json-stringify to handle arrays starts increasing exponentially, leading to slow overall executions.

Settings

In order to improve that the user can set the largeArrayMechanism and largeArraySize options.

largeArrayMechanism's default value is default. Valid values for it are:

  • default - This option is a compromise between performance and feature set by still providing the expected functionality out of this lib but giving up some possible performance gain. With this option set, large arrays would be stringified by joining their stringified elements using Array.join instead of string concatenation for better performance
  • json-stringify - This option will remove support for schema validation within large arrays completely. By doing so the overhead previously mentioned is nulled, greatly improving execution time. Mind there's no change in behavior for arrays not considered large

largeArraySize's default value is 20000. Valid values for it are integer-like values, such as:

  • 20000
  • 2e4
  • '20000'
  • '2e4' - note this will be converted to 2, not 20000
  • 1.5 - note this will be converted to 1

Unsafe string

By default, the library escapes all strings. With the 'unsafe' format, the string isn't escaped. This has a potentially dangerous security issue. You can use it only if you are sure that your data doesn't need escaping. The advantage is a significant performance improvement.

Example:

const stringify = fastJson({
  title: 'Example Schema',
  type: 'object',
  properties: {
    'code': {
      type: 'string',
      format: 'unsafe'
    }
  }
})
Benchmarks

For reference, here are some benchmarks for comparison over the three mechanisms. Benchmarks were conducted on an old machine.

  • Machine: ST1000LM024 HN-M 1TB HDD, Intel Core i7-3610QM @ 2.3GHz, 12GB RAM, 4C/8T.
  • Node.js v16.13.1
JSON.stringify large array x 157 ops/sec ±0.73% (86 runs sampled)
fast-json-stringify large array default x 48.72 ops/sec ±4.92% (48 runs sampled)
fast-json-stringify large array json-stringify x 157 ops/sec ±0.76% (86 runs sampled)
compile-json-stringify large array x 175 ops/sec ±4.47% (79 runs sampled)
AJV Serialize large array x 58.76 ops/sec ±4.59% (60 runs sampled)

Security notice

Treat the schema definition as application code, it is not safe to use user-provided schemas.

To achieve low cost and high performance redaction fast-json-stringify creates and compiles a function (using the Function constructor) on initialization. While the schema is currently validated for any developer errors, there is no guarantee that supplying user-generated schema could not expose your application to remote attacks.

Users are responsible for sending trusted data. fast-json-stringify guarantees that you will get a valid output only if your input matches the schema or can be coerced to the schema. If your input doesn't match the schema, you will get undefined behavior.

Debug Mode

The debug mode can be activated during your development to understand what is going on when things do not work as you expect.

const debugCompiled = fastJson({
  title: 'default string',
  type: 'object',
  properties: {
    firstName: {
      type: 'string'
    }
  }
}, { mode: 'debug' })

console.log(debugCompiled) // it is a object contain code, ajv instance
const rawString = debugCompiled.code // it is the generated code
console.log(rawString)

const stringify = fastJson.restore(debugCompiled) // use the generated string to get back the `stringify` function
console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"Foo"}'

Standalone Mode

The standalone mode is used to compile the code that can be directly run by node itself. You need to have fast-json-stringify installed for the standalone code to work.

const fs = require('fs')
const code = fastJson({
  title: 'default string',
  type: 'object',
  properties: {
    firstName: {
      type: 'string'
    }
  }
}, { mode: 'standalone' })

fs.writeFileSync('stringify.js', code)
const stringify = require('stringify.js')
console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"Foo"}'

Acknowledgments

This project was kindly sponsored by nearForm.

License

Licensed under MIT.

: { type: 'string' } } }) const obj = { nickname: 'nick', matchfoo: 42, otherfoo: 'str', matchnum: 3 } console.log(stringify(obj)) // '{"matchfoo":"42","otherfoo":"str","matchnum":3,"nickname":"nick"}'

Additional properties

__INLINE_CODE_63__ supports additional properties as defined by JSON schema. additionalProperties must be an object or a boolean, declared in this way: __INLINE_CODE_64__. additionalProperties will work only for the properties that are not explicitly listed in the properties and patternProperties objects.

If additionalProperties is not present or is set to __INLINE_CODE_65__, every property that is not explicitly listed in the properties and patternProperties objects will be ignored, as described in Missing fields. Missing fields are ignored to avoid having to rewrite objects before serializing. However, other schema rules would throw in similar situations. If additionalProperties is set to __INLINE_CODE_66__, it will be used by __INLINE_CODE_67__ to stringify the additional properties. If you want to achieve maximum performance, we strongly encourage you to use a fixed schema where possible. The additional properties will always be serialized at the end of the object. Example:

__CODE_BLOCK_8__
AnyOf and OneOf

__INLINE_CODE_68__ supports the anyOf and oneOf keywords as defined by JSON schema. Both must be an array of valid JSON schemas. The different schemas will be tested in the specified order. The more schemas __INLINE_CODE_69__ has to try before finding a match, the slower it will be.

anyOf and oneOf use ajv as a JSON schema validator to find the schema that matches the data. This has an impact on performance—only use it as a last resort.

Example:

__CODE_BLOCK_9__

When specifying object JSON schemas for anyOf, add required validation keyword to match only the objects with the properties you want.

Example:

__CODE_BLOCK_10__

If/then/else

__INLINE_CODE_70__ supports __INLINE_CODE_71__ jsonschema feature. See ajv documentation.

Example:

__CODE_BLOCK_11__

NB Do not declare the properties twice or you will print them twice!

Reuse - $ref

If you want to reuse a definition of a value, you can use the property __INLINE_CODE_72__. The value of __INLINE_CODE_73__ must be a string in JSON Pointer format. Example:

__CODE_BLOCK_12__

If you need to use an external definition, you can pass it as an option to __INLINE_CODE_74__. Example:

__CODE_BLOCK_13__

External definitions can also reference each other. Example:

__CODE_BLOCK_14__

Long integers

By default, the library will handle automatically BigInt.

Integers

The __INLINE_CODE_75__ property will be truncated if a floating point is provided. You can customize this behavior with the __INLINE_CODE_76__ option that will accept __INLINE_CODE_77__, __INLINE_CODE_78__, __INLINE_CODE_79__, or __INLINE_CODE_80__. Default is __INLINE_CODE_81__:

__CODE_BLOCK_15__

Nullable

According to the Open API 3.0 specification, a value that can be null must be declared __INLINE_CODE_82__.

Nullable object
__CODE_BLOCK_16__

Otherwise, instead of raising an error, null values will be coerced as follows:

  • __INLINE_CODE_83__ -> __INLINE_CODE_84__
  • __INLINE_CODE_85__ -> __INLINE_CODE_86__
  • __INLINE_CODE_87__ -> __INLINE_CODE_88__
  • __INLINE_CODE_89__ -> __INLINE_CODE_90__
  • __INLINE_CODE_91__ -> __INLINE_CODE_92__
  • __INLINE_CODE_93__ -> __INLINE_CODE_94__

Large Arrays

Large arrays are, for the scope of this document, defined as arrays containing, by default, __INLINE_CODE_95__ elements or more. That value can be adjusted via the option parameter __INLINE_CODE_96__.

At some point the overhead caused by the default mechanism used by __INLINE_CODE_97__ to handle arrays starts increasing exponentially, leading to slow overall executions.

Settings

In order to improve that the user can set the __INLINE_CODE_98__ and __INLINE_CODE_99__ options.

__INLINE_CODE_100__'s default value is __INLINE_CODE_101__. Valid values for it are:

  • __INLINE_CODE_102__ - This option is a compromise between performance and feature set by still providing the expected functionality out of this lib but giving up some possible performance gain. With this option set, large arrays would be stringified by joining their stringified elements using __INLINE_CODE_103__ instead of string concatenation for better performance
  • __INLINE_CODE_104__ - This option will remove support for schema validation within large arrays completely. By doing so the overhead previously mentioned is nulled, greatly improving execution time. Mind there's no change in behavior for arrays not considered large

__INLINE_CODE_105__'s default value is __INLINE_CODE_106__. Valid values for it are integer-like values, such as:

  • __INLINE_CODE_107__
  • __INLINE_CODE_108__
  • __INLINE_CODE_109__
  • __INLINE_CODE_110__ - note this will be converted to __INLINE_CODE_111__, not __INLINE_CODE_112__
  • __INLINE_CODE_113__ - note this will be converted to __INLINE_CODE_114__

Unsafe string

By default, the library escapes all strings. With the 'unsafe' format, the string isn't escaped. This has a potentially dangerous security issue. You can use it only if you are sure that your data doesn't need escaping. The advantage is a significant performance improvement.

Example:

__CODE_BLOCK_17__
Benchmarks

For reference, here are some benchmarks for comparison over the three mechanisms. Benchmarks were conducted on an old machine.

  • Machine: __INLINE_CODE_115__.
  • Node.js __INLINE_CODE_116__
__CODE_BLOCK_18__

Security notice

Treat the schema definition as application code, it is not safe to use user-provided schemas.

To achieve low cost and high performance redaction __INLINE_CODE_117__ creates and compiles a function (using the __INLINE_CODE_118__ constructor) on initialization. While the __INLINE_CODE_119__ is currently validated for any developer errors, there is no guarantee that supplying user-generated schema could not expose your application to remote attacks.

Users are responsible for sending trusted data. __INLINE_CODE_120__ guarantees that you will get a valid output only if your input matches the schema or can be coerced to the schema. If your input doesn't match the schema, you will get undefined behavior.

Debug Mode

The debug mode can be activated during your development to understand what is going on when things do not work as you expect.

__CODE_BLOCK_19__

Standalone Mode

The standalone mode is used to compile the code that can be directly run by __INLINE_CODE_121__ itself. You need to have __INLINE_CODE_122__ installed for the standalone code to work.

__CODE_BLOCK_20__

Acknowledgments

This project was kindly sponsored by nearForm.

License

Licensed under MIT.

: { type: 'string' } }, additionalProperties: { type: 'string' } }) const obj = { nickname: 'nick', matchfoo: 42, otherfoo: 'str', matchnum: 3, nomatchstr: 'valar morghulis', nomatchint: 313 } console.log(stringify(obj)) // '{"nickname":"nick","matchfoo":"42","otherfoo":"str","matchnum":3,"nomatchstr":"valar morghulis",nomatchint:"313"}'
AnyOf and OneOf

__INLINE_CODE_68__ supports the anyOf and oneOf keywords as defined by JSON schema. Both must be an array of valid JSON schemas. The different schemas will be tested in the specified order. The more schemas __INLINE_CODE_69__ has to try before finding a match, the slower it will be.

anyOf and oneOf use ajv as a JSON schema validator to find the schema that matches the data. This has an impact on performance—only use it as a last resort.

Example:

__CODE_BLOCK_9__

When specifying object JSON schemas for anyOf, add required validation keyword to match only the objects with the properties you want.

Example:

__CODE_BLOCK_10__

If/then/else

__INLINE_CODE_70__ supports __INLINE_CODE_71__ jsonschema feature. See ajv documentation.

Example:

__CODE_BLOCK_11__

NB Do not declare the properties twice or you will print them twice!

Reuse - $ref

If you want to reuse a definition of a value, you can use the property __INLINE_CODE_72__. The value of __INLINE_CODE_73__ must be a string in JSON Pointer format. Example:

__CODE_BLOCK_12__

If you need to use an external definition, you can pass it as an option to __INLINE_CODE_74__. Example:

__CODE_BLOCK_13__

External definitions can also reference each other. Example:

__CODE_BLOCK_14__

Long integers

By default, the library will handle automatically BigInt.

Integers

The __INLINE_CODE_75__ property will be truncated if a floating point is provided. You can customize this behavior with the __INLINE_CODE_76__ option that will accept __INLINE_CODE_77__, __INLINE_CODE_78__, __INLINE_CODE_79__, or __INLINE_CODE_80__. Default is __INLINE_CODE_81__:

__CODE_BLOCK_15__

Nullable

According to the Open API 3.0 specification, a value that can be null must be declared __INLINE_CODE_82__.

Nullable object
__CODE_BLOCK_16__

Otherwise, instead of raising an error, null values will be coerced as follows:

  • __INLINE_CODE_83__ -> __INLINE_CODE_84__
  • __INLINE_CODE_85__ -> __INLINE_CODE_86__
  • __INLINE_CODE_87__ -> __INLINE_CODE_88__
  • __INLINE_CODE_89__ -> __INLINE_CODE_90__
  • __INLINE_CODE_91__ -> __INLINE_CODE_92__
  • __INLINE_CODE_93__ -> __INLINE_CODE_94__

Large Arrays

Large arrays are, for the scope of this document, defined as arrays containing, by default, __INLINE_CODE_95__ elements or more. That value can be adjusted via the option parameter __INLINE_CODE_96__.

At some point the overhead caused by the default mechanism used by __INLINE_CODE_97__ to handle arrays starts increasing exponentially, leading to slow overall executions.

Settings

In order to improve that the user can set the __INLINE_CODE_98__ and __INLINE_CODE_99__ options.

__INLINE_CODE_100__'s default value is __INLINE_CODE_101__. Valid values for it are:

  • __INLINE_CODE_102__ - This option is a compromise between performance and feature set by still providing the expected functionality out of this lib but giving up some possible performance gain. With this option set, large arrays would be stringified by joining their stringified elements using __INLINE_CODE_103__ instead of string concatenation for better performance
  • __INLINE_CODE_104__ - This option will remove support for schema validation within large arrays completely. By doing so the overhead previously mentioned is nulled, greatly improving execution time. Mind there's no change in behavior for arrays not considered large

__INLINE_CODE_105__'s default value is __INLINE_CODE_106__. Valid values for it are integer-like values, such as:

  • __INLINE_CODE_107__
  • __INLINE_CODE_108__
  • __INLINE_CODE_109__
  • __INLINE_CODE_110__ - note this will be converted to __INLINE_CODE_111__, not __INLINE_CODE_112__
  • __INLINE_CODE_113__ - note this will be converted to __INLINE_CODE_114__

Unsafe string

By default, the library escapes all strings. With the 'unsafe' format, the string isn't escaped. This has a potentially dangerous security issue. You can use it only if you are sure that your data doesn't need escaping. The advantage is a significant performance improvement.

Example:

__CODE_BLOCK_17__
Benchmarks

For reference, here are some benchmarks for comparison over the three mechanisms. Benchmarks were conducted on an old machine.

  • Machine: __INLINE_CODE_115__.
  • Node.js __INLINE_CODE_116__
__CODE_BLOCK_18__

Security notice

Treat the schema definition as application code, it is not safe to use user-provided schemas.

To achieve low cost and high performance redaction __INLINE_CODE_117__ creates and compiles a function (using the __INLINE_CODE_118__ constructor) on initialization. While the __INLINE_CODE_119__ is currently validated for any developer errors, there is no guarantee that supplying user-generated schema could not expose your application to remote attacks.

Users are responsible for sending trusted data. __INLINE_CODE_120__ guarantees that you will get a valid output only if your input matches the schema or can be coerced to the schema. If your input doesn't match the schema, you will get undefined behavior.

Debug Mode

The debug mode can be activated during your development to understand what is going on when things do not work as you expect.

__CODE_BLOCK_19__

Standalone Mode

The standalone mode is used to compile the code that can be directly run by __INLINE_CODE_121__ itself. You need to have __INLINE_CODE_122__ installed for the standalone code to work.

__CODE_BLOCK_20__

Acknowledgments

This project was kindly sponsored by nearForm.

License

Licensed under MIT.

: { type: 'string' } } }) const obj = { nickname: 'nick', matchfoo: 42, otherfoo: 'str', matchnum: 3 } console.log(stringify(obj)) // '{"matchfoo":"42","otherfoo":"str","matchnum":3,"nickname":"nick"}'

Additional properties

__INLINE_CODE_63__ supports additional properties as defined by JSON schema. additionalProperties must be an object or a boolean, declared in this way: __INLINE_CODE_64__. additionalProperties will work only for the properties that are not explicitly listed in the properties and patternProperties objects.

If additionalProperties is not present or is set to __INLINE_CODE_65__, every property that is not explicitly listed in the properties and patternProperties objects will be ignored, as described in Missing fields. Missing fields are ignored to avoid having to rewrite objects before serializing. However, other schema rules would throw in similar situations. If additionalProperties is set to __INLINE_CODE_66__, it will be used by __INLINE_CODE_67__ to stringify the additional properties. If you want to achieve maximum performance, we strongly encourage you to use a fixed schema where possible. The additional properties will always be serialized at the end of the object. Example:

__CODE_BLOCK_8__
AnyOf and OneOf

__INLINE_CODE_68__ supports the anyOf and oneOf keywords as defined by JSON schema. Both must be an array of valid JSON schemas. The different schemas will be tested in the specified order. The more schemas __INLINE_CODE_69__ has to try before finding a match, the slower it will be.

anyOf and oneOf use ajv as a JSON schema validator to find the schema that matches the data. This has an impact on performance—only use it as a last resort.

Example:

__CODE_BLOCK_9__

When specifying object JSON schemas for anyOf, add required validation keyword to match only the objects with the properties you want.

Example:

__CODE_BLOCK_10__

If/then/else

__INLINE_CODE_70__ supports __INLINE_CODE_71__ jsonschema feature. See ajv documentation.

Example:

__CODE_BLOCK_11__

NB Do not declare the properties twice or you will print them twice!

Reuse - $ref

If you want to reuse a definition of a value, you can use the property __INLINE_CODE_72__. The value of __INLINE_CODE_73__ must be a string in JSON Pointer format. Example:

__CODE_BLOCK_12__

If you need to use an external definition, you can pass it as an option to __INLINE_CODE_74__. Example:

__CODE_BLOCK_13__

External definitions can also reference each other. Example:

__CODE_BLOCK_14__

Long integers

By default, the library will handle automatically BigInt.

Integers

The __INLINE_CODE_75__ property will be truncated if a floating point is provided. You can customize this behavior with the __INLINE_CODE_76__ option that will accept __INLINE_CODE_77__, __INLINE_CODE_78__, __INLINE_CODE_79__, or __INLINE_CODE_80__. Default is __INLINE_CODE_81__:

__CODE_BLOCK_15__

Nullable

According to the Open API 3.0 specification, a value that can be null must be declared __INLINE_CODE_82__.

Nullable object
__CODE_BLOCK_16__

Otherwise, instead of raising an error, null values will be coerced as follows:

  • __INLINE_CODE_83__ -> __INLINE_CODE_84__
  • __INLINE_CODE_85__ -> __INLINE_CODE_86__
  • __INLINE_CODE_87__ -> __INLINE_CODE_88__
  • __INLINE_CODE_89__ -> __INLINE_CODE_90__
  • __INLINE_CODE_91__ -> __INLINE_CODE_92__
  • __INLINE_CODE_93__ -> __INLINE_CODE_94__

Large Arrays

Large arrays are, for the scope of this document, defined as arrays containing, by default, __INLINE_CODE_95__ elements or more. That value can be adjusted via the option parameter __INLINE_CODE_96__.

At some point the overhead caused by the default mechanism used by __INLINE_CODE_97__ to handle arrays starts increasing exponentially, leading to slow overall executions.

Settings

In order to improve that the user can set the __INLINE_CODE_98__ and __INLINE_CODE_99__ options.

__INLINE_CODE_100__'s default value is __INLINE_CODE_101__. Valid values for it are:

  • __INLINE_CODE_102__ - This option is a compromise between performance and feature set by still providing the expected functionality out of this lib but giving up some possible performance gain. With this option set, large arrays would be stringified by joining their stringified elements using __INLINE_CODE_103__ instead of string concatenation for better performance
  • __INLINE_CODE_104__ - This option will remove support for schema validation within large arrays completely. By doing so the overhead previously mentioned is nulled, greatly improving execution time. Mind there's no change in behavior for arrays not considered large

__INLINE_CODE_105__'s default value is __INLINE_CODE_106__. Valid values for it are integer-like values, such as:

  • __INLINE_CODE_107__
  • __INLINE_CODE_108__
  • __INLINE_CODE_109__
  • __INLINE_CODE_110__ - note this will be converted to __INLINE_CODE_111__, not __INLINE_CODE_112__
  • __INLINE_CODE_113__ - note this will be converted to __INLINE_CODE_114__

Unsafe string

By default, the library escapes all strings. With the 'unsafe' format, the string isn't escaped. This has a potentially dangerous security issue. You can use it only if you are sure that your data doesn't need escaping. The advantage is a significant performance improvement.

Example:

__CODE_BLOCK_17__
Benchmarks

For reference, here are some benchmarks for comparison over the three mechanisms. Benchmarks were conducted on an old machine.

  • Machine: __INLINE_CODE_115__.
  • Node.js __INLINE_CODE_116__
__CODE_BLOCK_18__

Security notice

Treat the schema definition as application code, it is not safe to use user-provided schemas.

To achieve low cost and high performance redaction __INLINE_CODE_117__ creates and compiles a function (using the __INLINE_CODE_118__ constructor) on initialization. While the __INLINE_CODE_119__ is currently validated for any developer errors, there is no guarantee that supplying user-generated schema could not expose your application to remote attacks.

Users are responsible for sending trusted data. __INLINE_CODE_120__ guarantees that you will get a valid output only if your input matches the schema or can be coerced to the schema. If your input doesn't match the schema, you will get undefined behavior.

Debug Mode

The debug mode can be activated during your development to understand what is going on when things do not work as you expect.

__CODE_BLOCK_19__

Standalone Mode

The standalone mode is used to compile the code that can be directly run by __INLINE_CODE_121__ itself. You need to have __INLINE_CODE_122__ installed for the standalone code to work.

__CODE_BLOCK_20__

Acknowledgments

This project was kindly sponsored by nearForm.

License

Licensed under MIT.

Keywords