cdimascio / express-openapi-validator

🦋 Auto-validates api requests, responses, and securities using ExpressJS and an OpenAPI 3.x specification
MIT License
885 stars 203 forks source link

Discriminator Issue #635

Open rallyRussell opened 2 years ago

rallyRussell commented 2 years ago

Describe the bug

Under certain conditions involving allOf and discriminator fields, OAS can't be resolved.

Describing this is difficult. It's best understood by looking at the examples and work around below.

To Reproduce

root.yaml

```yaml openapi: 3.0.3 info: title: Test description: |- Test version: 1.2.3 paths: "/api/test": get: summary: Test operationId: test description: |- Test responses: "200": description: OK content: application/json: schema: type: object properties: price: anyOf: - $ref: "common/components/schemas/currency/CurrencyA.yaml" - $ref: "common/components/schemas/currency/CurrencyB.yaml" - $ref: "common/components/schemas/currency/CurrencyC.yaml" discriminator: propertyName: currencyType mapping: CurrencyA: "common/components/schemas/currency/CurrencyA.yaml" CurrencyB: "common/components/schemas/currency/CurrencyB.yaml" CurrencyC: "common/components/schemas/currency/CurrencyC.yaml" ```

Currency.yaml

```yaml title: Currency allOf: - $ref: "CurrencyBase.yaml" ```

CurrencyBase.yaml

```yaml title: Currency - Base type: object properties: amount: type: string currencyType: type: string ```

Applies to the latest version - 4.12.14

Actual behavior When launching the back end application, the following line is shown:

$ref: keywords ignored in schema at path "#"

When making a query to any endpoint, the following error is shown:

{
    "message": "can't resolve reference #/paths/~1api~1test/get/responses/200/content/application~1json/schema/properties/price/anyOf/0/allOf/0 from id #"
}

Expected behavior Error free validation.

Examples and context I've investigated a bit to thoroughly understand how this error is occurring. I've found two ways that do not cause an error.

In the root.yaml file above, simply remove the discriminator field (and all child fields) and validation works as expected.

In the root.yaml file above, change the schema of the price object from:

price:
  <currenySchemaWithDiscriminator>

to

price:
  type: array
  items:
    <currenySchemaWithDiscriminator>
alonsohki commented 2 years ago

This seems to be a bug when combining discriminators with references. In https://github.com/cdimascio/express-openapi-validator/blob/master/src/middlewares/parsers/schema.preprocessor.ts#L318 a properties field is added to the schema, even if empty. Then, ajv will detect that you have a object containing a $ref key along with an empty properties key, and trigger this piece of code that generates the said warning:

  if (it.schema.$ref && $refKeywords) {
    if (it.opts.extendRefs == 'fail') {
      throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)');
    } else if (it.opts.extendRefs !== true) {
      $refKeywords = false;
      it.logger.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"');
    }
  }
alonsohki commented 2 years ago

I have created a PR to fix this: https://github.com/cdimascio/express-openapi-validator/pull/651