OpenAPI Schema vs JSON Schema
How an OpenAPI 3.1 Schema Object differs from a JSON Schema document, including dialect, added keywords, and the two definitions of integer.
An OpenAPI Schema Object and a JSON Schema document can describe the same JSON value and still be different files. OpenAPI 3.1.0 bases its data types on JSON Schema Draft 2020-12 and says the Schema Object is a superset of that draft. The superset is the comparison: JSON Schema keywords apply, and an OpenAPI document adds a dialect, a short list of extended keywords, and an HTTP API around the schema. This note is about which file you are holding. What an API schema constrains is the field layer inside either file. What a validator does with format is the check, and it is a separate question from the file type.
Which file you are holding
An OpenAPI document describes an HTTP API. Its root is an OpenAPI Object. The openapi field is required. It is the version of the OpenAPI Specification the document uses, and the specification says it is not related to info.version. The info object is required. The specification recommends the file names openapi.json and openapi.yaml. It does not say a parser must reject another name.
Message shapes inside that document are Schema Objects. components.schemas is a map of reusable Schema Objects. Paths, webhooks, servers, and security requirements are fields of the API document. They are not JSON Schema keywords, and they do not become keywords by sitting in the same file as a schema.
A JSON Schema document describes a JSON instance. Draft 2020-12 says every schema has a meta-schema, which can be declared with the $schema keyword. That keyword is both a dialect identifier and the identifier of a resource which is itself a schema: the schema that describes which schemas are valid for that dialect. The value must be a URI. The keyword should be used on the document root schema. If it is absent from the document root, the specification says the resulting behavior is implementation-defined. That sentence belongs to JSON Schema. OpenAPI states a different default for Schema Objects that live inside an OpenAPI document, and the next section is that default.
The illustration below is not a captured API. It shows the two roots. The $schema value in the first object is the value Draft 2020-12 uses in its own output examples.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"sku": { "type": "string" }
}
}
{
"openapi": "3.1.0",
"info": { "title": "Illustration", "version": "1" },
"components": {
"schemas": {
"Item": {
"type": "object",
"properties": {
"sku": { "type": "string" }
}
}
}
}
}
Illustration, not a captured message. The first root is a schema. The second root is an OpenAPI document that contains a schema. info.version here is a placeholder string, not a compatibility rule.
Putting the first object under components.schemas reuses the schema. It does not turn the bare file into an API description. How a version records a compatibility promise is where info.version belongs. The openapi field does not answer it.
What the superset commits you to
In the OpenAPI 3.1.0 data-types section, data types are based on the types supported by JSON Schema Draft 2020-12. The Schema Object is described there, and again in its own section, as a superset of that draft. Unless stated otherwise, Schema Object properties follow JSON Schema and do not add semantics. Where JSON Schema says behavior is defined by the application, for example for annotations, OpenAPI also leaves that behavior to the application that consumes the OpenAPI document.
The dialect is more specific than the word “superset.” OpenAPI says the Schema Object dialect requires the OAS base vocabulary, in addition to the vocabularies in the JSON Schema Draft 2020-12 general-purpose meta-schema. The dialect for this version of the specification is identified by https://spec.openapis.org/oas/3.1/dialect/base. The specification calls that URI the OAS dialect schema id.
Which dialect a tool must apply depends on where the schema sits.
$schema may appear on any root Schema Object. If it is present, OpenAPI says it must be used to determine the dialect. That is how a Schema Object can comply with a JSON Schema draft other than the default Draft 2020-12. Tooling must support the OAS dialect schema id. It may support other values of $schema. Support for a second dialect is allowed, not required.
The OpenAPI Object may set jsonSchemaDialect. That value is the default $schema for Schema Objects contained in the document, and it must be a URI. If jsonSchemaDialect is not set, the OAS dialect schema id must be used for those Schema Objects. A $schema on a Schema Object overrides that default.
A schema outside the OpenAPI document follows different rules. When the reference target is not an OAS document, OpenAPI’s example is a bare JSON Schema resource, and $schema in that resource must follow JSON Schema rules. A bare file with no $schema does not pick up the OAS dialect id because an OpenAPI document points at it. A validator on that file and a validator on a Schema Object inside the document are not promised the same default. The validation note already records that under schema drift: two files that share a name can still be different dialects.
Keywords the OpenAPI dialect adds
OpenAPI names two JSON Schema properties whose definitions it extends:
descriptionmay use CommonMark.formatkeeps the formats JSON Schema defines, and OpenAPI adds predefined formats of its own. The data-types table listsint32andint64oninteger,floatanddoubleonnumber, andpasswordonstring. The comment onpasswordis a hint to user interfaces to obscure input.
The OAS base vocabulary, in the Schema Object fixed fields, is four keywords:
discriminatoradds support for polymorphism. It names a property used to differentiate schemas that may satisfy the payload.xmlmay be used only on property schemas. It has no effect on root schemas.externalDocspoints at further documentation for the schema.exampleis a free-form instance. OpenAPI deprecates it in favor of the JSON Schemaexampleskeyword, discourages its use, and says later versions of the specification may remove it.
The Schema Object also supports keywords from other vocabularies, or entirely arbitrary properties. It may be extended with specification extensions, and inside this object those additional properties may omit the x- prefix.
OpenAPI lists discriminator, xml, and externalDocs in the OAS base vocabulary. They are not in the pair of JSON Schema properties it says it extended, description and format. Tooling must support the OAS dialect. This desk treats a tool that drops an unknown keyword and still reports the instance as valid as silence, not as acceptance. Whether format rejects a bad string is the same kind of silence unless the dialect asserts formats. That case stays in the validation note.
JSON Schema’s type is a string or an array of unique strings. OpenAPI 3.1.0 lists description and format as the properties it extends, and does not list type. This desk reads that list as leaving the JSON Schema definition of type in place, including the array form. The reading classifies the published list. It is not a second definition of type.
Two definitions of integer
Both documents define an integer type. The sentences are not the same.
JSON Schema Validation says the string values of type must be one of the six primitive types, null, boolean, object, array, number, or string, or integer, which matches any number with a zero fractional part.
OpenAPI 3.1.0 says integer as a type is also supported and is defined as a JSON number without a fraction or exponent part.
This note does not treat the two sentences as one rule, and it does not claim that a given literal passes one and fails the other. If two stacks generate the client and the server, write down which sentence the contract uses. A field labeled only “integer” has not made that choice.
| Question | Where it is answered | Easy mix-up |
|---|---|---|
| Is this file an HTTP API description? | An OpenAPI root, with openapi and info |
Reading a bare schema as an API |
| Which dialect applies inside an OpenAPI document? | $schema on the root Schema Object, otherwise jsonSchemaDialect, otherwise the OAS dialect schema id |
Assuming Draft 2020-12 from the mention alone |
| Which dialect applies to a bare external schema? | JSON Schema rules for $schema |
Giving a bare file the OAS default |
May description be CommonMark? |
OpenAPI’s extension of that property | Expecting markdown in every renderer |
What does integer match? |
The sentence in the dialect you named | Validating with the other sentence |
The middle column is a classification used by this desk. The dialect order and the integer sentences are the cited documents. The right-hand column is not a measurement of how often the mix-up happens.
A checklist before you treat the files as the same
Use this when a repository contains both an OpenAPI document and a schema file. It is a review list, not a score.
- If the root has
openapiandinfo, read it as an OpenAPI document. If the root is a schema, read it as a JSON Schema resource. - Inside the OpenAPI document, record the dialect actually in force:
$schemaif the root Schema Object has one, otherwisejsonSchemaDialect, otherwisehttps://spec.openapis.org/oas/3.1/dialect/base. - Do not copy that default onto a bare external file. If that file has no
$schema, JSON Schema says the behavior is implementation-defined. Name the dialect in the file, or name the implementation you tested. discriminator,xml,externalDocs, andexampleare OpenAPI vocabulary. Silence from a JSON Schema-only tool is not a passing check.- CommonMark in
description, and the formatsint32,int64,float,double, andpassword, are OpenAPI extensions.passwordis a hint to obscure input. Whetherformatrejects a value stays in the validation note. - Write the
integersentence you mean, or name the dialect, instead of the word alone. - Status codes, paths, and security stay on the OpenAPI operation. The schema note’s table is the longer list of what a schema leaves open.
Open questions
OpenAPI 3.1.0 requires tooling to support the OAS dialect schema id and allows other $schema values. It does not say that a particular generator does either. A generator that accepts only one draft URI is showing its own limit. Test it against the dialect URI you publish, where you already test validation. This note does not report what any version after 3.1.0 did with the deprecated example keyword.
Sources
- OpenAPI Specification 3.1.0 — OpenAPI Initiative
- JSON Schema Core, Draft 2020-12, section 8.1.1 ($schema) — JSON Schema
- JSON Schema Core, Draft 2020-12, section 8.1 (meta-schemas) — JSON Schema
- JSON Schema Core, Draft 2020-12, section 12.4 (output examples) — JSON Schema
- JSON Schema Validation, Draft 2020-12, section 6.1.1 (type) — JSON Schema