Gathering detailed insights and metrics for @ardatan/fast-json-stringify
Gathering detailed insights and metrics for @ardatan/fast-json-stringify
Gathering detailed insights and metrics for @ardatan/fast-json-stringify
Gathering detailed insights and metrics for @ardatan/fast-json-stringify
npm install @ardatan/fast-json-stringify
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
3,519 Stars
730 Commits
208 Forks
32 Watching
9 Branches
102 Contributors
Updated on 28 Nov 2024
Minified
Minified + Gzipped
JavaScript (98.5%)
TypeScript (1.5%)
Cumulative downloads
Total Downloads
Last day
-11.8%
1,542
Compared to previous day
Last week
-1.6%
10,635
Compared to previous week
Last month
141.2%
47,493
Compared to previous month
Last year
19.7%
265,111
Compared to previous year
3
2
fast-json-stringify is significantly faster than JSON.stringify()
for small payloads.
Its performance advantage shrinks as your payload grows.
It pairs well with flatstr, which triggers a V8 optimization that improves performance when eventually converting the string to a Buffer
.
fast-json-stringify requires a JSON Schema Draft 7 input to generate a fast stringify
function.
EX41S-SSD, Intel Core i7, 4Ghz, 64GB RAM, 4C/8T, SSD
.v18.12.1
FJS creation x 4,129 ops/sec ±0.82% (92 runs sampled)
CJS creation x 184,196 ops/sec ±0.12% (97 runs sampled)
AJV Serialize creation x 61,130,591 ops/sec ±0.40% (92 runs sampled)
JSON.stringify array x 5,057 ops/sec ±0.10% (100 runs sampled)
fast-json-stringify array default x 6,243 ops/sec ±0.14% (98 runs sampled)
fast-json-stringify array json-stringify x 6,261 ops/sec ±0.30% (99 runs sampled)
compile-json-stringify array x 6,842 ops/sec ±0.18% (96 runs sampled)
AJV Serialize array x 6,964 ops/sec ±0.11% (95 runs sampled)
JSON.stringify large array x 248 ops/sec ±0.07% (90 runs sampled)
fast-json-stringify large array default x 99.96 ops/sec ±0.22% (74 runs sampled)
fast-json-stringify large array json-stringify x 248 ops/sec ±0.07% (90 runs sampled)
compile-json-stringify large array x 317 ops/sec ±0.09% (89 runs sampled)
AJV Serialize large array x 111 ops/sec ±0.07% (33 runs sampled)
JSON.stringify long string x 16,002 ops/sec ±0.09% (98 runs sampled)
fast-json-stringify long string x 15,979 ops/sec ±0.09% (96 runs sampled)
compile-json-stringify long string x 15,952 ops/sec ±0.31% (97 runs sampled)
AJV Serialize long string x 21,416 ops/sec ±0.08% (98 runs sampled)
JSON.stringify short string x 12,944,272 ops/sec ±0.09% (96 runs sampled)
fast-json-stringify short string x 30,585,790 ops/sec ±0.27% (97 runs sampled)
compile-json-stringify short string x 30,656,406 ops/sec ±0.12% (96 runs sampled)
AJV Serialize short string x 30,406,785 ops/sec ±0.37% (96 runs sampled)
JSON.stringify obj x 3,153,043 ops/sec ±0.33% (99 runs sampled)
fast-json-stringify obj x 6,866,434 ops/sec ±0.11% (100 runs sampled)
compile-json-stringify obj x 15,886,723 ops/sec ±0.15% (98 runs sampled)
AJV Serialize obj x 8,969,043 ops/sec ±0.36% (97 runs sampled)
JSON stringify date x 1,126,547 ops/sec ±0.09% (97 runs sampled)
fast-json-stringify date format x 1,836,188 ops/sec ±0.12% (99 runs sampled)
compile-json-stringify date format x 1,125,735 ops/sec ±0.19% (98 runs sampled)
Example
Options
API
fastJsonStringify
Specific use cases
Required
Missing fields
Pattern Properties
Additional Properties
AnyOf
and OneOf
Reuse - $ref
Long integers
Integers
Nullable
Large Arrays
Security Notice
Debug Mode
Standalone Mode
Acknowledgements
License
Try it out on RunKit: https://runkit.com/npm/fast-json-stringify
1const fastJson = require('fast-json-stringify') 2const stringify = fastJson({ 3 title: 'Example Schema', 4 type: 'object', 5 properties: { 6 firstName: { 7 type: 'string' 8 }, 9 lastName: { 10 type: 'string' 11 }, 12 age: { 13 description: 'Age in years', 14 type: 'integer' 15 }, 16 reg: { 17 type: 'string' 18 } 19 } 20}) 21 22console.log(stringify({ 23 firstName: 'Matteo', 24 lastName: 'Collina', 25 age: 32, 26 reg: /"([^"]|\\")*"/ 27}))
Optionally, you may provide to fast-json-stringify
an option object as second parameter:
1const fastJson = require('fast-json-stringify') 2const stringify = fastJson(mySchema, { 3 schema: { ... }, 4 ajv: { ... }, 5 rounding: 'ceil' 6})
schema
: external schemas references by $ref property. More detailsajv
: ajv v8 instance's settings for those properties that require ajv
. More detailsrounding
: setup how the integer
types will be rounded when not integers. More detailslargeArrayMechanism
: set the mechanism that should be used to handle large
(by default 20000
or more items) arrays. More detailsBuild a stringify()
function based on jsonschema draft 7 spec.
Supported types:
'string'
'integer'
'number'
'array'
'object'
'boolean'
'null'
And nested ones, too.
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 string formatted Date and not Date Object, there will be no manipulation on it. It should be properly formatted.
Example with a Date object:
1const stringify = fastJson({ 2 title: 'Example Schema with string date-time field', 3 type: 'string', 4 format: 'date-time' 5}) 6 7const date = new Date() 8console.log(stringify(date)) // '"YYYY-MM-DDTHH:mm:ss.sssZ"'
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:
1const schema = { 2 title: 'Example Schema with required field', 3 type: 'object', 4 properties: { 5 nickname: { 6 type: 'string' 7 }, 8 mail: { 9 type: 'string' 10 } 11 }, 12 required: ['mail'] 13}
If the object to stringify is missing the required field(s), fast-json-stringify
will throw an error.
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:
1const stringify = fastJson({ 2 title: 'Example Schema', 3 type: 'object', 4 properties: { 5 nickname: { 6 type: 'string' 7 }, 8 mail: { 9 type: 'string' 10 } 11 } 12}) 13 14const obj = { 15 mail: 'mail@example.com' 16} 17 18console.log(stringify(obj)) // '{"mail":"mail@example.com"}'
fast-json-stringify
supports default
jsonschema key in order to serialize a value
if it is undefined
or not present.
Example:
1const stringify = fastJson({ 2 title: 'Example Schema', 3 type: 'object', 4 properties: { 5 nickname: { 6 type: 'string', 7 default: 'the default string' 8 } 9 } 10}) 11 12console.log(stringify({})) // '{"nickname":"the default string"}' 13console.log(stringify({nickname: 'my-nickname'})) // '{"nickname":"my-nickname"}'
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:
1const stringify = fastJson({ 2 title: 'Example Schema', 3 type: 'object', 4 properties: { 5 nickname: { 6 type: 'string' 7 } 8 }, 9 patternProperties: { 10 'num': { 11 type: 'number' 12 }, 13 '.*foo$': { 14 type: 'string' 15 } 16 } 17}) 18 19const obj = { 20 nickname: 'nick', 21 matchfoo: 42, 22 otherfoo: 'str', 23 matchnum: 3 24} 25 26console.log(stringify(obj)) // '{"matchfoo":"42","otherfoo":"str","matchnum":3,"nickname":"nick"}'
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:
1const stringify = fastJson({ 2 title: 'Example Schema', 3 type: 'object', 4 properties: { 5 nickname: { 6 type: 'string' 7 } 8 }, 9 patternProperties: { 10 'num': { 11 type: 'number' 12 }, 13 '.*foo$': { 14 type: 'string' 15 } 16 }, 17 additionalProperties: { 18 type: 'string' 19 } 20}) 21 22const obj = { 23 nickname: 'nick', 24 matchfoo: 42, 25 otherfoo: 'str', 26 matchnum: 3, 27 nomatchstr: 'valar morghulis', 28 nomatchint: 313 29} 30 31console.log(stringify(obj)) // '{"nickname":"nick","matchfoo":"42","otherfoo":"str","matchnum":3,"nomatchstr":"valar morghulis",nomatchint:"313"}'
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:
1const stringify = fastJson({ 2 title: 'Example Schema', 3 type: 'object', 4 properties: { 5 'undecidedType': { 6 'anyOf': [{ 7 type: 'string' 8 }, { 9 type: 'boolean' 10 }] 11 } 12 } 13})
When specifying object JSON schemas for anyOf, add required validation keyword to match only the objects with the properties you want.
Example:
1const stringify = fastJson({ 2 title: 'Example Schema', 3 type: 'array', 4 items: { 5 anyOf: [ 6 { 7 type: 'object', 8 properties: { 9 savedId: { type: 'string' } 10 }, 11 // without "required" validation any object will match 12 required: ['savedId'] 13 }, 14 { 15 type: 'object', 16 properties: { 17 error: { type: 'string' } 18 }, 19 required: ['error'] 20 } 21 ] 22 } 23})
fast-json-stringify
supports if/then/else
jsonschema feature. See ajv documentation.
Example:
1const stringify = fastJson({ 2 'type': 'object', 3 'properties': { 4 }, 5 'if': { 6 'properties': { 7 'kind': { 'type': 'string', 'enum': ['foobar'] } 8 } 9 }, 10 'then': { 11 'properties': { 12 'kind': { 'type': 'string', 'enum': ['foobar'] }, 13 'foo': { 'type': 'string' }, 14 'bar': { 'type': 'number' } 15 } 16 }, 17 'else': { 18 'properties': { 19 'kind': { 'type': 'string', 'enum': ['greeting'] }, 20 'hi': { 'type': 'string' }, 21 'hello': { 'type': 'number' } 22 } 23 } 24}) 25 26console.log(stringify({ 27 kind: 'greeting', 28 foo: 'FOO', 29 bar: 42, 30 hi: 'HI', 31 hello: 45 32})) // {"kind":"greeting","hi":"HI","hello":45} 33console.log(stringify({ 34 kind: 'foobar', 35 foo: 'FOO', 36 bar: 42, 37 hi: 'HI', 38 hello: 45 39})) // {"kind":"foobar","foo":"FOO","bar":42}
NB Do not declare the properties twice or you will print them twice!
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:
1const schema = { 2 title: 'Example Schema', 3 definitions: { 4 num: { 5 type: 'object', 6 properties: { 7 int: { 8 type: 'integer' 9 } 10 } 11 }, 12 str: { 13 type: 'string' 14 } 15 }, 16 type: 'object', 17 properties: { 18 nickname: { 19 $ref: '#/definitions/str' 20 } 21 }, 22 patternProperties: { 23 'num': { 24 $ref: '#/definitions/num' 25 } 26 }, 27 additionalProperties: { 28 $ref: '#/definitions/def' 29 } 30} 31 32const stringify = fastJson(schema)
If you need to use an external definition, you can pass it as an option to fast-json-stringify
.
Example:
1const schema = { 2 title: 'Example Schema', 3 type: 'object', 4 properties: { 5 nickname: { 6 $ref: 'strings#/definitions/str' 7 } 8 }, 9 patternProperties: { 10 'num': { 11 $ref: 'numbers#/definitions/num' 12 } 13 }, 14 additionalProperties: { 15 $ref: 'strings#/definitions/def' 16 } 17} 18 19const externalSchema = { 20 numbers: { 21 definitions: { 22 num: { 23 type: 'object', 24 properties: { 25 int: { 26 type: 'integer' 27 } 28 } 29 } 30 } 31 }, 32 strings: require('./string-def.json') 33} 34 35const stringify = fastJson(schema, { schema: externalSchema })
External definitions can also reference each other. Example:
1const schema = { 2 title: 'Example Schema', 3 type: 'object', 4 properties: { 5 foo: { 6 $ref: 'strings#/definitions/foo' 7 } 8 } 9} 10 11const externalSchema = { 12 strings: { 13 definitions: { 14 foo: { 15 $ref: 'things#/definitions/foo' 16 } 17 } 18 }, 19 things: { 20 definitions: { 21 foo: { 22 type: 'string' 23 } 24 } 25 } 26} 27 28const stringify = fastJson(schema, { schema: externalSchema })
By default the library will handle automatically BigInt.
The type: integer
property will be truncated if a floating point is provided.
You can customize this behaviour with the rounding
option that will accept round
, ceil
, floor
or trunc
. Default is trunc
:
1const stringify = fastJson(schema, { rounding: 'ceil' })
According to the Open API 3.0 specification, a value that can be null must be declared nullable
.
1const stringify = fastJson({ 2 'title': 'Nullable schema', 3 'type': 'object', 4 'nullable': true, 5 'properties': { 6 'product': { 7 'nullable': true, 8 'type': 'object', 9 'properties': { 10 'name': { 11 'type': 'string' 12 } 13 } 14 } 15 } 16}) 17 18console.log(stringify({product: {name: "hello"}})) // "{"product":{"name":"hello"}}" 19console.log(stringify({product: null})) // "{"product":null}" 20console.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 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.
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 performancejson-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 largelargeArraySize
'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
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:
1const stringify = fastJson({ 2 title: 'Example Schema', 3 type: 'object', 4 properties: { 5 'code': { 6 type: 'string', 7 format 'unsafe' 8 } 9 } 10})
For reference, here goes some benchmarks for comparison over the three mechanisms. Benchmarks conducted on an old machine.
ST1000LM024 HN-M 1TB HDD, Intel Core i7-3610QM @ 2.3GHz, 12GB RAM, 4C/8T
.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)
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.
The debug mode can be activated during your development to understand what is going on when things do not work as you expect.
1const debugCompiled = fastJson({ 2 title: 'default string', 3 type: 'object', 4 properties: { 5 firstName: { 6 type: 'string' 7 } 8 } 9}, { mode: 'debug' }) 10 11console.log(debugCompiled) // it is a object contain code, ajv instance 12const rawString = debugCompiled.code // it is the generated code 13console.log(rawString) 14 15const stringify = fastJson.restore(debugCompiled) // use the generated string to get back the `stringify` function 16console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"Foo"}'
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.
1const fs = require('fs') 2const code = fastJson({ 3 title: 'default string', 4 type: 'object', 5 properties: { 6 firstName: { 7 type: 'string' 8 } 9 } 10}, { mode: 'standalone' }) 11 12fs.writeFileSync('stringify.js', code) 13const stringify = require('stringify.js') 14console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"Foo"}'
This project was kindly sponsored by nearForm.
MIT
No vulnerabilities found.
Reason
9 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
0 existing vulnerabilities detected
Reason
security policy file detected
Details
Reason
Found 13/22 approved changesets -- score normalized to 5
Reason
SAST tool is not run on all commits -- score normalized to 5
Details
Reason
dangerous workflow patterns detected
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
project is not fuzzed
Details
Score
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More