Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add schemas for 3.1 #2489

Merged
merged 7 commits into from
Mar 25, 2021
Merged

Add schemas for 3.1 #2489

merged 7 commits into from
Mar 25, 2021

Conversation

jdesrosiers
Copy link
Contributor

@jdesrosiers jdesrosiers commented Mar 2, 2021

Progress on #2474 has stalled out while @philsturgeon is busy saving the world, so this is an alternative so we can keep things moving.

The schema.yaml schema doesn't validate the JSON Schemas in your OpenAPI document because 3.1 allows you to use any JSON Schema dialect you choose. I also included schema-base.yaml that extends the main schema to validate that all schemas use the default OAS base vocabulary.

The test suite is included as a git submodule of https://github.com/Mermade/openapi3-examples.

npx mocha test.js

You can also validate a document individually.

node validate.js path/to/document/to/validate.yaml

@MikeRalphson
Copy link
Member

MikeRalphson commented Mar 3, 2021

Looking good - could we move non-test scripts into /scripts/{function} and tests into a new /test or /scripts/test directory please? That will make syncing up with #1911 and adding things like linting easier.

Just a note that the openapi3-examples repo is licensed Apache-2.0 specifically in case we preferred to bring in those examples directly instead of the submodule approach.

@jdesrosiers
Copy link
Contributor Author

jdesrosiers commented Mar 3, 2021

the openapi3-examples repo is licensed Apache-2.0 specifically in case we preferred to bring in those examples directly instead of the submodule approach.

I think it would be best to bring those in rather than use a submodule. I used a submodule for now because I figured it was the easiest way to pull in your updates until this PR gets merged.

The main schema no longer validates schemas other than verifying that
they are either a schema or an object.
@jdesrosiers
Copy link
Contributor Author

I realized that I closed #2467 because those schemas are included here as well, but there were some important questions included there that need to be answered, so I'm copying them over to this issue.


Here's a candidate for the OAS 3.1 Base Schema vocabulary and dialect meta-schemas.

I wasn't quite sure what to names things. The directory and file names are intended to match the $ids. Both the dialect and the vocabulary are called "base", which is awkward, but it seemed the most accurate based on the language in the spec. Let me know if you prefer different names or flatter structure.

The "base" vocabulary is set to false in the dialect schema. This allows validators to validate instances against this meta-schema even if it doesn't know about the OpenAPI extensions. This is no concern for most of the extensions because they are just annotations and don't affect validation. The exception is discriminator. In that case, the discriminator keyword will be quietly skipped by a validator. If you prefer users get an error in this case, let me know and I'll switch that to true.

In JSON Schema, format is annotation-only by default. I wasn't sure if OpenAPI 3.1 expects format to be annotation-only or for it to validate against the format. Currently, it's set to annotation-only. Let me know if you rather it validate.

I didn't explicitly add the additional format values that OpenAPI 3.1 adds because JSON Schema Draft 2020-10 already allows any value, so there was nothing to do.

If you want to run this through its paces, head over to https://json-schema.hyperjump.io. Add two additional schema tabs using the [+] button next to the "Schema" tab. Add one of the schemas in this PR to each tab. In the original tab, change the value of the $schema keyword to https://spec.openapis.org/oas/3.1/dialect/base. That schema will then meta-validate using these meta-schemas. For example, you can add a discriminator and see that you get an error if the propertyName field is missing. You can also modify the meta-schemas if you want to try to modify anything. You can leave the "Instance" tab(s) empty, validating an instance works, but it's not relevant to the meta-schemas.

@kadeatfox
Copy link

@jdesrosiers Quick question about something that was mentioned in the TSC today:

We will stop getting questions about interdependencies between parameters

Is there a way to do this with this pr?

@jdesrosiers
Copy link
Contributor Author

@kadeatfox I think what was meant there was that we are now expressing some of the dependencies between parameters in the schema. The hope is that more people will answer their own question by validating against the schema and seeing if it passes or fails.

@kadeatfox
Copy link

@jdesrosiers could you give me an example of how those dependencies could be expressed? I must've missed it in the meeting.

@jdesrosiers
Copy link
Contributor Author

@kadeatfox Remember all those if/then blocks at /$defs/parameter/dependentSchemas/schema/$defs? They say things like, if the "in" property is present in a Parameter Object with the value of "header", then the "style" property can only have the value "simple". If "in" was another value, then "style" is allowed to have different values. In other words, the "style" property is dependent on the "in" property. That kind was constraint was not expressed in schemas for previous versions.

That's what I thought he was talking about, but I could be mistaken.

@kadeatfox
Copy link

Thanks @jdesrosiers that's what I was following as well.

For a moment though, I took it to mean define dependencies between parameters for the API an OAS Document means to describe. Sounds like he was referring to the ability to define the OAS itself.

schemas/v3.1/schema.yaml Outdated Show resolved Hide resolved
@kadeatfox
Copy link

kadeatfox commented Mar 18, 2021

@jdesrosiers perhaps if you're interested in more testing, you could use: https://github.com/APIs-guru/openapi-directory/tree/master/APIs as a good bank of examples for valid api specs. At least the most recent documents that conform to OAS 3.0+

@MikeRalphson would that be a good repository of "test fixtures" for this PR?

@MikeRalphson
Copy link
Member

They would need to be upgraded to v3.1 first, and my converter is still a work-in-progress.

@jdesrosiers
Copy link
Contributor Author

jdesrosiers commented Mar 22, 2021

Status Update

Since we're not getting much feedback on this, it was decided to release what we have and release fixes when issues come up. Before this is merged, here are some things everyone should be aware of including some decisions I've made because no one else has expressed an opinion.

  1. The OpenAPI Schema Object dialect and OAS base vocabulary is defined in JSON. There is no YAML version.
  2. The OAS base vocabulary is set as an optional vocabulary. This means that you will be able to validate a schema object with a draft 2020-12 validator that doesn't understand the OAS base vocabulary. However, this is only a good idea if discriminator doesn't affect validation. The spec has some contradictory wording, but the wording that calls discriminator a "hint" leads me to interpret that it should be used for optimization and not change validation results.
  3. The OAS base vocabulary uses the annotation-only version of the format keyword just like draft 2020-12.
  4. The OpenAPI schema is written in YAML. The JSON version should not be edited manually. It will be generated from the YAML.
  5. The $id of the OpenAPI schema is date based. I used the date when it was first created, but it should probably be updated to the date it's released when it's time to merge.
  6. When released, all of the schemas defined here should be retrievable from the URI specified by their $id. (This is not required, but it's good practice).
  7. The OpenAPI schema doesn't validate schema objects
  8. I've also included an additional schema that extends the standard schema to validate schema objects using the OpenAPI Schema Object dialect. This can also be used as an example for how others can create a schema that validates schema objects using their preferred JSON Schema dialect.
  9. I included a validate.js script and a test.js with test cases donated by @MikeRalphson. I originally did this for my benefit in creating the schema, but I'm keeping them around in hopes that they are useful for others. Instructions on how to use the scripts are in schema/3.1/README.md. If we want to keep the tests around, it would be a good idea to add them to whatever CI process might already be in place.
  10. Finally, everyone should be aware that these schemas are still only very lightly tested. You can bet that there are still bugs.

Well, that was much longer than I expected, so I hope it actually gets read.

@MikeRalphson MikeRalphson merged commit 0f9d3ec into OAI:master Mar 25, 2021
@jdesrosiers jdesrosiers deleted the oas31-schema-2 branch March 25, 2021 17:43
@seriousme
Copy link
Contributor

Hi,

I have tried to validate a 3.1 spec against 3.1 schema using Ajv-cli using npx ajv test -s schemas/v3.1/schema.json -d examples/v3.0/petstore.json --valid --validate-formats=false --spec=draft2020

This resulted in 79 errors because Ajv thinks the 3.1 spec schema is not a valid draft-2020 spec.
Ajv does not even get to the point where it tries to validate the petstore example because of the errors in 3.1 spec schema.

The errors are listed below.
Are these true errors in the 3.1 spec schema or are these bugs in Ajv ?
(draft 2020 is a rather recent addition ;-))

Kind regards,
Hans

strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/encoding/$defs/explod
e-default/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/encoding/$defs/expl
ode-default/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/encoding/$defs/expl
ode-default/then" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/encoding/$defs/expl
ode-default/else" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependentSc
hemas/schema/$defs/styles-for-path/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-path/if" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependentSc
hemas/schema/$defs/styles-for-path/then" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-path/then" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependentSc
hemas/schema/$defs/styles-for-header/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-header/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-header/then" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependentSc
hemas/schema/$defs/styles-for-query/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-query/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-query/then" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependentSc
hemas/schema/$defs/styles-for-cookie/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-cookie/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-cookie/then" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependentSc
hemas/schema/$defs/styles-for-form/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-form/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-form/then" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/parameter/dependent
Schemas/schema/$defs/styles-for-form/else" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$defs
/type-apikey/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$de
fs/type-apikey/if" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$defs
/type-apikey/then" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$de
fs/type-apikey/then" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$defs
/type-http/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$de
fs/type-http/if" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$defs
/type-http/then" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$de
fs/type-http/then" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$defs
/type-http-bearer/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$de
fs/type-http-bearer/if" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$defs
/type-http-bearer/then" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/security-scheme/$de
fs/type-http-bearer/then" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/then" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/then" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "patternProperties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/$defs/specificatio
n-extensions" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/if" (strictTypes)
strict mode: missing type "object" for keyword "required" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/then" (strictTypes)
strict mode: missing type "object" for keyword "properties" at "https://spec.openapis.org/oas/3.1/schema/2021-04-15#/then" (strictTypes)
schema schemas/v3.1/schema.json is invalid
error: strict mode: property schemas matches pattern ^(schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks|pathItems)$ (use allowMatchingProperties)

@jdesrosiers
Copy link
Contributor Author

@seriousme The schema is valid. Ajv appears to be applying some non-standard linting rules. It seems that it requires "type": "object" to be declared in any schema that uses object keywords such as properties and required. While that's the right thing to do in general, it's not the best thing for some advanced patterns this schema makes use of.

For example, here's the "specification-extensions" definition.

{
  "patternProperties": {
    "^x-": true
  }
}

It's not intended to be used by itself, it's a mix-in to be combined with other schemas. If we included "type": "object" in this schema, it would duplicate the "type": "object" in the schema being extended which is not ideal. For example, here is the "paths" definition which includes the "specification-extensions" mix-in. It already declares the type. The mix-in doesn't need to as well.

{
  "type": "object",
  "patternProperties": {
    "^/": { "$ref": "#/$defs/path-item" }
  },
  "$ref": "#/$defs/specification-extensions",
  "unevaluatedProperties": false
}

Ajv does these extra linting rules as part of "strict mode". Clearly the strict mode linting rules still need some tweaking. I suggest turning strict mode off for now.

@seriousme
Copy link
Contributor

Thx for the quick response !

turning off strictTypes by using:
npx ajv test -s schemas/v3.1/schema.json -d test/v3.0/petstore.json --valid --validate-formats=false --spec=draft2020 --strictTypes=false

solves most of the issues except for one:

error: strict mode: property schemas matches pattern ^(schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks|pathItems)$ (use allowMatchingProperties)

Maybe I'm wrong but what I think you are trying to specify here is:

  • you can have any propertyname, except for the predefined ones.

If that is the case then this regexp works for me:

"^((?!(schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks|pathItems)).)*$"

To replace "^(schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks|pathItems)$"

Once I replace the regexp Ajv starts parsing petstore.json from the 3.0 examples, so the openapi version triggers an error on 3.0 as expected.

Kind regards,
Hans

@jdesrosiers
Copy link
Contributor Author

The schema is correct. Again, this looks like another strict mode linting rule. It appears that this rule ensures that properties only match the properties keyword or the patternProperties keyword, and not both. This part of the schema matches both on purpose.

The Components Object is the toughest part of the schema to understand because it has some complex constraints. The Components Object is an object with several defined properties whose values are objects whose keys match ^[a-zA-Z0-9._-]+$ and whose values are a different type of object. Here's a truncated version of what the Components Object schema would look like if we didn't use patternProperties.

{
  "type": "object",
  "properties": {
    "schemas": {
      "type": "object",
      "additionalProperties": { "$dynamicRef": "#meta" },
      "propertyNames": { "pattern": "^[a-zA-Z0-9._-]+$" }
    },
    "responses": {
      "type": "object",
      "additionalProperties": { "$ref": "#/$defs/response-or-reference" },
      "propertyNames": { "pattern": "^[a-zA-Z0-9._-]+$" }
    },
  },
  "$ref": "#/$defs/specification-extensions",
  "unevaluatedProperties": false
}

Notice how "propertyNames": { "pattern": "^[a-zA-Z0-9._-]+$" } is duplicated across each of the properties schemas. patternProperties was used to eliminate that duplication. The following says, if the property name is "schemas" or "responses", then the object that is the value of the property should only have keys that match ^[a-zA-Z0-9._-]+$.

"patternProperties": {
  "^(schemas|responses)$": {
    "propertyNames": { "pattern": "^[a-zA-Z0-9._-]+$" }
  }

We can't have the patternProperties match all properties because then we can't forbid unevaluated properties, hence the whitelist. The other way to deal with the duplication would have been to make it a definition and reference it in each schema.

{
  "type": "object",
  "properties": {
    "schemas": {
      "type": "object",
      "additionalProperties": { "$dynamicRef": "#meta" },
      "$ref": "#/$defs/component-names"
    },
    "responses": {
      "type": "object",
      "additionalProperties": { "$ref": "#/$defs/response-or-reference" },
      "$ref": "#/$defs/component-names"
    },
  },
  "$ref": "#/$defs/specification-extensions",
  "unevaluatedProperties": false
}

This would have been more verbose, but effectively the same amount of duplication and easier to understand. In retrospect, maybe that would have been better, but either way, the schema is valid and works as intended despite ajv's overzealous linting rules.

@seriousme
Copy link
Contributor

Many thanks again for taking the time to write the elaborate explanation !
I learned a lot from these responses !

Kind regards,
Hans

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants