redocly-cli icon indicating copy to clipboard operation
redocly-cli copied to clipboard

no-invalid-media-type-examples not working in a basic case with anyOf

Open LasneF opened this issue 1 year ago • 5 comments

Describe the bug

given a sample with anyOf and required statement example validation fails whereas it is valid

To Reproduce validate the below OAS Spec (in the Additional context section) launching redocly lint spec.yml

validation fails with the error failed with 2 errors and 9 warnings.

it shoot about schema: must NOT have unevaluated properties lastName

and Example value must conform to the schema: must NOT have unevaluated properties address.

29 | }, 30 | "example": { 31 | "address": "someWhere",

vs address is mentioned as required , looks it does not like the anyOf syntax

dropping the anyOf make it ok

Expected behavior

no validation warning toward this sample sample has been tested with several json schema validator ( json-schema.hyperjump.io , json-everything.net , liquid'

Logs

Redocly Version(s) redocly 1.25.2 ( on Windows)

Additional context

{
    "openapi": "3.1.0",
    "info": {
        "title": "this is the title",
        "description": "this is the description",
        "version": "1.0"
    },
    "license": {
        "description": "dd"
    },
    "servers": [
        {
            "url": "https://api.server.test/v1"
        }
    ],
    "paths": {
        "/v1/users": {
            "get": {
                "summary": "Get user info",
                "description": "Returns all details about a given user.",
                "operationId": "getUser",
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/User"
                                },
                                "example": {
                                    "address": "someWhere",
                                    "firstName": "John",
                                    "lastName": "Doe"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "empty"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "User": {
                "description": "Details of a user",
                "type": "object",
                "required": [
                    "address"
                ],
                "properties": {
                    "address": {
                        "type": "string"
                    }
                },
                "anyOf": [
                    {
                        "type": "object",
                        "required": [
                            "firstName",
                            "lastName"
                        ],
                        "properties": {
                            "firstName": {
                                "type": "string"
                            },
                            "lastName": {
                                "type": "string"
                            }
                        }
                    },
                    {
                        "type": "object",
                        "required": [
                            "name"
                        ],
                        "properties": {
                            "name": {
                                "type": "string"
                            }
                        }
                    }
                ]
            }
        }
    }
}

LasneF avatar Sep 16 '24 16:09 LasneF

This is a duplicate of https://github.com/Redocly/redocly-cli/issues/1658. Feel free to add any additional details there.

tatomyr avatar Sep 17 '24 07:09 tatomyr

Wait, this is a separate issue. It goes away if we move address under each of the subschemas of anyOf. However, those syntaxes are equivalent, so the behaviour should be the same. The actual issue is that having properties and anyOf at the same time breaks the logic.

tatomyr avatar Sep 17 '24 13:09 tatomyr

this requires the rules related to example validation to be modified

anyOf with a sibling additionalProperties: false doesn't allow any properties to be defined in that instance. this line is causing that behavior.

https://github.com/Redocly/redocly-cli/blob/36161d76112779a5ce37289c9f063a35abb91a4e/packages/core/src/rules/ajv.ts#L26C7-L26C35

an example of what the schema is transformed to by Redocly

$schema: 'https://json-schema.org/draft/2020-12/schema'
properties:
  address:
    type: string
anyOf: [{}, {}]
additionalProperties: false // this is added by Redocly to all example schemas and it causes the example to fail, particularly when composition keywords are used at the root of the schema (anyOf, allOf, oneOf)

If we modify the rule, the example passes validation.

extends:
  - recommended

rules:
  no-invalid-media-type-examples:
    severity: warn
    allowAdditionalProperties: true
{
    "openapi": "3.1.0",
    "info": {
        "title": "this is the title",
        "description": "this is the description",
        "version": "1.0"
    },
    "license": {
        "description": "dd"
    },
    "servers": [
        {
            "url": "https://api.server.test/v1"
        }
    ],
    "paths": {
        "/v1/users": {
            "get": {
                "summary": "Get user info",
                "description": "Returns all details about a given user.",
                "operationId": "getUser",
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/User"
                                },
                                "examples": {
                                    "example": {
                                        "value": {
                                        "address": "someWhere",
                                        "firstName": "John",
                                        "lastName": "Doe"}
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "empty"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "User": {
                "description": "Details of a user",
                "type": "object",
                "required": [
                    "address"
                ],
                "properties": {
                    "address": {
                        "type": "string"
                    }
                },
                "anyOf": [
                    {
                        "type": "object",
                        "required": [
                            "firstName",
                            "lastName"
                        ],
                        "properties": {
                            "firstName": {
                                "type": "string"
                            },
                            "lastName": {
                                "type": "string"
                            }
                        }
                    },
                    {
                        "type": "object",
                        "required": [
                            "name"
                        ],
                        "properties": {
                            "name": {
                                "type": "string"
                            }
                        }
                    }
                ]
            }
        }
    }
}

jeremyfiel avatar Oct 21 '24 14:10 jeremyfiel

Btw.. the allowAdditionalProperties implementation is really only useful for OAS 3.0.x (json schema draft-04) when using the keyword additionalProperties

OAS 3.1.x. introduced full support of json schema 2020-12, and a new keyword unevaluatedProperties. this keyword has the ability to see into subschemas defined in a composition keyword (anyOf, allOf). if Redocly is going to constrain examples to use some form of unevaluatedProperties: false or additionalProperties: false, the proper keyword should be used for OAS 3.1.x schemas. >> unevaluatedProperties: false

an example with OAS 3.0.x

$schema: 'http://json-schema.org/draft-04/schema#'
properties:
  address:
    type: string
anyOf:
- properties:
    firstName: 
      type: string
- properties:
    name:
      type: string
additionalProperties: false // any instance will fail this schema because additionalProperties and anyOf are siblings. 

valid

address: test

invalid

address: test
firstName: larry

an example with OAS 3.1.x

$schema: 'https://json-schema.org/draft/2020-12/schema'
properties:
  address:
    type: string
anyOf:
-  properties:
     firstName: 
       type: string
-  properties:
     name:
       type: string
unevaluatedProperties: false // any instance with `address`, `firstName` or `name` will pass validation.. any other keyword included will fail validation

valid

address: test
firstName: larry
name: Jose

invalid

address: test
firstName: larry
name: Jose
age: 1

jeremyfiel avatar Oct 21 '24 14:10 jeremyfiel

@tatomyr any update for this one looks @jeremyfiel a definitive expert on schema provides a convincing solution

LasneF avatar Feb 28 '25 15:02 LasneF

Fix for this case has been merged in https://github.com/Redocly/redocly-cli/pull/2404 and released with @redocly/cli v2.11.1. I’ve verified that the original example from this issue now passes as expected.

@LasneF @jeremyfiel Marking this as resolved, but feel free to comment if you still see any problems after upgrading.

vadyvas avatar Nov 11 '25 13:11 vadyvas