JSON schema imports
Schema combination provides one mechanism for the reuse of schemas, by providing the ability to create a schema that logically extends and overrides one or more other schemas. The import mechanism gives you another way to reuse a schema, by creating a shared schema for common pieces and then importing that schema in order to reference its types.
Schema import and schema combine both provide units of reuse. A code analogy would be that the combine instruction is the equivalent of subclassing a given class while the import instruction is the equivalent of merely referencing that class in arguments or return types. Imports always exist in a separate logical namespace. If A imports B, definitions in A and B that have the same name are still two different types.
By contrast, schema combination exists in a single namespace. That is, if A combines B, definitions in A that have the same name as definitions in B are combined together to produce a single definition. From the point of view of downstream systems, everything ends up merged together anyway. Hence, the choice between the import instruction and the combine instruction really comes down to whether you want definitions with the same name to be merged together or not. When you are logically extending a schema, such as creating a custom schema that extends a base configuration schema, you want the combination behavior. If you are referencing a shared schema authored by another team for another purpose, you probably do not want that behavior. In this case, keep the namespaces separate so that you do not have to worry about name conflicts producing unexpected results.
Import syntax
# symbol. For example, the following
Contact schema imports an Address
schema:{
"$schema": "http://json-schema.org/draft-04/schema#",
"x-gw-import" : {
"address" : "gw.px.ete.address-1.0"
},
"definitions": {
"Contact" : {
"type" : "object",
"properties" : {
"EmailAddress1" : {
"type" : "string"
},
"HomePhone" : {
"type" : "string"
},
"HomePhoneCountry" : {
"type" : "string",
"x-gw-type" : "typekey.PhoneCountryCode"
},
"AllAddresses" : {
"type" : "array",
"items" : {
"$ref" : "address#/definitions/Address"
}
},
"PrimaryAddress" : {
"$ref" : "address#/definitions/Address"
}
}
}
}
}address alias to point to the Address extension
schema:{
"$schema": "http://json-schema.org/draft-04/schema#",
"x-gw-combine" : ["gw.px.ete.contact-1.0"],
"x-gw-import" : {
"address" : "customer.address-1.0"
}
}That
override then causes all address references inherited from the base contact schema to
resolve to definitions in the customer.address-1.0 schema rather than the
gw.px.ete.address-1.0 schema.Externalizing schemas
JSON schema files are often externalized either by running the genExternalSchemas command-line task or in the context of producing a Swagger schema that imports the JSON schema. When the files are externalized in this way, imports are automatically inlined to create a single schema file. Imports are also treated this way for XSD translation. The intention is to make any given schema self-contained for use by downstream tools. No optimal way exists to define JSON schema file imports in a stable way that all tools can understand.
While import mechanisms technically exist for XSDs, they are not always easy to operate with various XSD toolchains. As a result, imports exist as a tool for schema authors to break down their schemas into reusable chunks. However, schema consumers always see a unified view of the schema.
Imports can lead to naming conflicts. For example, the Contact schema could define its own type inline called User. At the same time, the Address schema could also have a type called User. The REST framework attempts to use unqualified definition names in cases where there are no conflicts. However, the framework adds prefixes to ensure names are unique in cases where there are name conflicts. In this case, the output schema uses both User from the Contact schema itself and address_User, the definition from the Address schema.
