fast-json-stringify

repository·main·Indexed 25 days ago

https://github.com/fastify/fast-json-stringify

A high-performance JSON stringifier that uses JSON Schema Draft 7 to pre-compile serialization functions, providing significantly faster performance than native JSON.stringify() for small payloads. It supports specialized types like Date, RegExp, and BigInt, and offers advanced configuration for integer rounding, large array mechanisms, and polymorphic schemas using anyOf and oneOf.

Tokens
3.7K
Snippets
13
Records
19
Agent score
37%

What's inside fast-json-stringify

  1. Use fast-json-stringify for high-performance JSON serialization

    main

    Use fast-json-stringify to achieve significantly faster JSON serialization than JSON.stringify() for small payloads. It works by requiring a JSON Schema Draft 7 to generate a specialized stringify function optimized for your specific data structure.

    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: /"([^\"]|\\\\")*"/
    }))
  2. Handle required fields in JSON Schema

    main

    To ensure specific fields are present during serialization, add the field names to the required array within your schema object. If the object passed to the stringify() function is missing any field listed in required, fast-json-stringify will throw an error.

    const schema = {
      title: 'Example Schema with required field',
      type: 'object',
      properties: {
        nickname: {
          type: 'string'
        },
        mail: {
          type: 'string'
        }
      },
      required: ['mail']
    }
  3. Use default values for missing fields

    main

    You can use the default JSON Schema key to provide a fallback value if a field is undefined or missing from the input object. This prevents the field from being omitted in the final JSON string.

    const stringify = fastJson({
      title: 'Example Schema',
      type: 'object',
      properties: {
        nickname: {
          type: 'string',
          default: 'the default string'
        }
      }
    })
    
    console.log(stringify({})) // '{"nickname":"the default string"}'
  4. Use anyOf and oneOf for polymorphic schemas

    main

    Support multiple schema possibilities using anyOf or oneOf. Both accept an array of schemas. The library tests schemas in the specified order until a match is found.

    Performance Warning: These keywords use ajv for validation, which is slower than standard serialization. Use them only when necessary. When using anyOf with objects, always include a required array in the sub-schemas to ensure correct matching.

    const stringify = fastJson({
      title: 'Example Schema',
      type: 'array',
      items: {
        anyOf: [
          {
            type: 'object',
            properties: { savedId: { type: 'string' } },
            required: ['savedId']
          },
          {
            type: 'object',
            properties: { error: { type: 'string' } },
            required: ['error']
          }
        ]
      }
    })
  5. Use Debug Mode to inspect generated code

    main

    You can activate debug mode during development by passing { mode: 'debug' } as the second argument to fastJson. This returns an object containing the generated code and the ajv instance instead of a stringify function. You can use fastJson.restore() to convert this object back into a functional stringify method.

    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"}'
  6. Use Standalone Mode to generate executable code

    main

    Standalone mode allows you to compile code that can be run directly by node. This is useful for pre-compiling stringifiers. Note that fast-json-stringify must still be installed in the environment where the standalone code is executed. Pass { mode: 'standalone' } as the second argument to fastJson to generate the code string.

    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"}'
  7. Handle nullable fields

    main

    To allow a field to be null, set nullable: true in its schema definition.

    If a field is not marked nullable but a null value is provided, the library will coerce the value to a type-specific default:

    • integer/number $\rightarrow$ 0
    • string $\rightarrow$ ""
    • boolean $\rightarrow$ false
    • object $\rightarrow$ {}
    • array $\rightarrow$ []
    const stringify = fastJson({
      'title': 'Nullable schema',
      'type': 'object',
      'nullable': true,
      'properties': {
        'product': {
          'nullable': true,
          'type': 'object',
          'properties': {
            'name': { 'type': 'string' }
          }
        }
      }
    })
  8. Reuse schemas with $ref

    main

    Use the $ref property to reuse definitions.

    • Internal definitions: Use JSON Pointer format (e.g., "#/definitions/name") to reference schemas within the same object.
    • External definitions: Pass an externalSchema object as the second argument to fastJsonStringify(schema, { schema: externalSchema }). References in the main schema can then point to keys in the external schema (e.g., "strings#/definitions/str").
    const schema = {
      title: 'Example Schema',
      type: 'object',
      properties: {
        nickname: { $ref: '#/definitions/str' }
      },
      definitions: {
        str: { type: 'string' }
      }
    }
    
    const stringify = fastJson(schema)
  9. Use unsafe string format for performance

    main

    By default, all strings are escaped to ensure valid JSON. If you are certain your data does not require escaping and you need a significant performance boost, you can use the format: 'unsafe' option on a string field.

    Warning: This can lead to security issues if the input data is not trusted.

    const stringify = fastJson({
      title: 'Example Schema',
      type: 'object',
      properties: {
        'code': {
          type: 'string',
          format: 'unsafe'
        }
      }
    })
  10. Optimize large array serialization

    main

    For arrays with many elements (default threshold is 20000), performance may degrade. You can tune this using two options:

    • largeArraySize: The threshold at which the large array mechanism kicks in. Default is 20000.
    • largeArrayMechanism:
      • default: Uses Array.join for better performance than string concatenation while maintaining schema validation.
      • json-stringify: Completely removes schema validation for the array elements. This provides the highest performance but sacrifices schema enforcement for those elements.
  11. Configure patternProperties and additionalProperties

    main

    Manage dynamic properties using patternProperties and additionalProperties:

    • patternProperties: An object where keys are regex strings and values are schema objects. It applies to properties not explicitly listed in the properties object.
    • additionalProperties:
      • If false (default) or not present: Properties not in properties or patternProperties are ignored.
      • If true: Uses JSON.stringify for extra properties (slower).
      • If an object: Defines a schema for extra properties. These are always serialized at the end of the object.
    const stringify = fastJson({
      title: 'Example Schema',
      type: 'object',
      properties: {
        nickname: { type: 'string' }
      },
      patternProperties: {
        'num': { type: 'number' },
        '.*foo$': { type: 'string' }
      },
      additionalProperties: { type: 'string' }
    })
  12. Configure integer rounding

    main

    When using type: 'integer', floating point numbers will be truncated by default. You can customize this behavior using the rounding option in the fastJsonStringify configuration object.

    Supported values:

    • trunc (default)
    • round
    • ceil
    • floor
    const stringify = fastJson(schema, { rounding: 'ceil' })