Ajv: Does not pick up default value if defined in $ref definition

Created on 7 Nov 2016  路  10Comments  路  Source: ajv-validator/ajv

What version of Ajv are you using? Does the issue happen if you use the latest version?
4.8.2

Ajv options object (see https://github.com/epoberezkin/ajv#options):

{
    allErrors: true,
    format: 'full',
    useDefaults: true
}

JSON Schema (please make it as small as possible to reproduce the issue):

{
    ...
    "properties": {
        "phone": {
            "$ref": "#/definitions/optionalPhone"
        },
       ...
    },
    "definitions": {
        "emptyString": {
            "type": "string",
            "maxLength": 0
        },
        "optionalPhone": {
            "anyOf": [
                { "format": "phone" },
                { "$ref": "#/definitions/emptyString" }
            ],
            "default": ""
        }
    }
}

Above will work only if I define default: "" within phone.

Data (please make it as small as posssible to reproduce the issue):

{}

Validation result, data AFTER validation, error messages:
Data after validation: {}
No errors. Just the default value is not set for phone.

What results did you expect?
{ phone: "" }

enhancement limitation

Most helpful comment

@epoberezkin this seems especially bad in the case of $merge (see https://github.com/epoberezkin/ajv-merge-patch/issues/16). I was attempting to use ajv-merge-patch to avoid the subtleties in using $ref with things like additionalProperties and default. It was working great until I realized that default values weren't being applied.

Can you explain why this is still an issue when using $merge/$patch? My assumption was that the internal representation would be flatly merged (and thus the default and dynamicDefaults keywords would behave as expected).


Example Schema

{
  $id: 'activities.create',
  $merge: {
    source: {
      $ref: 'base.create',
    },
    with: {
      type: 'object',
      required: [
        'entitySubType',

        'name',
        'endDateTime',
        'startDateTime',
      ],
      additionalProperties: false,
      properties: {
        attributes: {
          type: 'object',
          default: {},
        },
        entityType: {
          type: 'string',
          const: EntityType.ACTIVITY,
          default: EntityType.ACTIVITY,
        },
        entitySubType: {
          $ref: 'types#/definitions/activityType',
        },
        name: { type: 'string' },
        endDateTime: {
          type: 'string',
          format: 'date-time',
        },
        startDateTime: {
          type: 'string',
          format: 'date-time',
        },
      },
    },
  },
}

In the above schema, neither the defaults from the referenced base.create schema nor the with block are applied.

All 10 comments

Yes, only from items and properties directly at the moment. It's a documented limitation: https://github.com/epoberezkin/ajv#assigning-defaults

Are there plans to apply defaults from references as well?

I see it as "nice to have" rather than something many users need. And it's quite complex. So there are no plans to implement it at the moment.

Even if you define properties in $refs, you can still define default values for the properties alongside $refs rather than inside: https://runkit.com/esp/5942f60cc72ffe0012805f9c

Thanks, I've tried that before but incorrectly (through allOf), which is why it wasn't working. IMO that's actually better than through Definitions.

through allOf it also works (unless you put default inside allOf). And it's not that putting default inside allOf is incorrect, it's just unsupported...

Yep, that's exactly what I've tried. Thanks again - I think it's even cleaner without allOf.

@epoberezkin this seems especially bad in the case of $merge (see https://github.com/epoberezkin/ajv-merge-patch/issues/16). I was attempting to use ajv-merge-patch to avoid the subtleties in using $ref with things like additionalProperties and default. It was working great until I realized that default values weren't being applied.

Can you explain why this is still an issue when using $merge/$patch? My assumption was that the internal representation would be flatly merged (and thus the default and dynamicDefaults keywords would behave as expected).


Example Schema

{
  $id: 'activities.create',
  $merge: {
    source: {
      $ref: 'base.create',
    },
    with: {
      type: 'object',
      required: [
        'entitySubType',

        'name',
        'endDateTime',
        'startDateTime',
      ],
      additionalProperties: false,
      properties: {
        attributes: {
          type: 'object',
          default: {},
        },
        entityType: {
          type: 'string',
          const: EntityType.ACTIVITY,
          default: EntityType.ACTIVITY,
        },
        entitySubType: {
          $ref: 'types#/definitions/activityType',
        },
        name: { type: 'string' },
        endDateTime: {
          type: 'string',
          format: 'date-time',
        },
        startDateTime: {
          type: 'string',
          format: 'date-time',
        },
      },
    },
  },
}

In the above schema, neither the defaults from the referenced base.create schema nor the with block are applied.

@marshall007 This question belongs in ajv-merge-patch. $merge is implemented as a custom keyword, it doesn't merge anything into the original schema. I don't plan to improve it until json-schema-org standardises it (or some other re-use mechanism).

@epoberezkin are there any workarounds for oneOf/allOf? It really limits some of our cases

Was this page helpful?
0 / 5 - 0 ratings