OAI / OpenAPI-Specification

The OpenAPI Specification Repository
https://openapis.org
Apache License 2.0
28.91k stars 9.07k forks source link

xml property and root schemas #1435

Open MikeRalphson opened 6 years ago

MikeRalphson commented 6 years ago

This is a question about the specification, and the intent of the following description in the Schema Object, relating to the xml property:

This MAY be used only on properties schemas. It has no effect on root schemas. Adds additional metadata to describe the XML representation of this property.

This has the effect of banning the construct

components:
  schemas:
    mySchema:
      type: object
      properties:
        a:
          type: string
      xml:
        name: xmlSchema

As a point-of-reference only, both swagger-ui and swagger-editor appear to honour this (useful) construct.

Is it possible to align the specification with real-world use for this case, and possibly move the restriction on xml properties on root schemas to those sub-properties (such as attribute and wrapped) where it seems to make sense?

MikeRalphson commented 6 years ago

This also raises the question: what is a "root schema"? The term is not defined elsewhere in the spec.

Given this fragment:

components:
  schemas:
    container:
      type: object
      properties:
        value:
          $ref: "#/components/schemas/value"
    value:
      type: object
      xml:
        name: errorValue
      properties:
        error:
         type: string

Is this allowed or prohibited (i.e. is value a "root schema")? Does value become a "root schema" if it is directly referenced (not from within a properties property?

fmvilas commented 6 years ago

Agree with @MikeRalphson. We can define the root schema as the first one "hanging" from a, for instance, Media Type Object schema property.

Given that schemas are reusable pieces, what is a root schema in one place will probably not be in another place. An example:

paths:
  /container:
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/container' # Here "value" is not root
  /value:
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/value' # Here "value" is root

components:
  schemas:
    container:
      type: object
      properties:
        value:
          $ref: "#/components/schemas/value"
    value:
      type: object
      xml:
        name: errorValue
      properties:
        error:
         type: string

So, from the schema perspective, there's no way to know if it will be root or not because there's no information about its context (and I think there should not be, to make them more reusable). This reminds me of the required property. It is defined in the parent schema because in some places it will be required and in some others, it will not.

components:
  schemas:
    container:
      type: object
      required:
        - somethingRequired
      properties:
        somethingRequired:
          type: string
silkentrance commented 6 years ago

I second that. The xml code generation hints must be available on the top level entities representing data types, and not just on the property level. Otherwise, one cannot customise the generated code.

And I would rather see this to be a part of the OAS 3.0.0 instead of some future release as it is currently being supported by Swagger 2.0 and we cannot migrate from that to OAS 3.0.0 without this feature.

And, according to the OP @MikeRalphson, OAS3 should differentiate between xml code generation hints on top level data types, items of arrayS and other properties.

Example

definitions:
  xml:
   type: object
   properties:
     name:
       type: string
     namespace:
       type: string
     prefix:
       type: string
  xmlOnProperty:
   allOf:
    - ./definitions/xml
    - type: object
       properties:
         attribute:
           type: boolean
           default: false
         wrapped:
           type: boolean
           default: false
handrews commented 5 years ago

@MikeRalphson JSON Schema 2019-09 has definitions for "schema document", "schema resource", "root schema", "schema object", and "subschema". It shouldn't be too hard to adapt that for the OAS situation of schema objects embedded in a non-schema document.

hrennau commented 3 years ago

It is helpful to be aware of the analogies between JSON Schema and XSD. What seems to be called here a "root schema" (if I understand the comments correctly) is named schemas, that is, the schemas contained by /components/schemas (V3) or /definitions (V2). They are equivalent to a named type definition in XSD. Such a type definition is used by element declarations or attribute declarations. The name of the item (corresponding to a JSON property name) is NEVER assigned by the type definition, always by the element/attribute declaration. These declarations are equivalent to the fields in a properties object. Like the name, also cardinality constraints can only be placed in those declarations, never in the types. Cardinality constraints are roughly equivalent to "required", @fmvilas - hence we only have to look at XSD and understand the equivalences in order to have a clear idea what belongs where. (Not that we could not do it differently, but we should think very carefully before doing it, and be aware of the deliberate deviation.)

And because of this analogy, it makes sense to me to keep the xml keyword out of "root schemas" = named schemas (alias type definitions): property naming is not the business of the type used to constrain the property value. Arguments in favor of allowing xml there in the interest of code generation should be reviewed crititically - they would have to be very convincing.

There is a real issue with translation into XML, which is the necessity to insert an XML root node, for which there is no correspondence in JSON. Currently, OAS foresees no possibility to control the invented name, leaving the integration developer in the lurch.

handrews commented 5 months ago

@OAI/tsc review request: Should we add support for this, or does the following example indicate that it's actually supposed to be supported already for named Components?


4.7.26.2.3 XML Attribute, Prefix and Namespace

In this example, a full model definition is shown.

Person:
  type: object
  properties:
    id:
      type: integer
      format: int32
      xml:
        attribute: true
    name:
      type: string
      xml:
        namespace: http://example.com/schema/sample
        prefix: sample
<Person id="123">
    <sample:name xmlns:sample="http://example.com/schema/sample">example</sample:name>
</Person>

The "full model" comment seems to contrast with the intro text of the whole series of XML examples:

The examples of the XML object definitions are included inside a property definition of a Schema Object with a sample of the XML representation of it.

But this "full model" example uses what looks like the name under #/components/schemas as the root XML element. Which does not rely on the xml keyword being used at the root.

Is this the intended solution?

lornajane commented 4 months ago

I'm in support of making OpenAPI more useful for those using XML format, and I think Mike's original suggestion of allowing xml in a root schema to support a name property, but disallowing some of its properties in that context is a sensible way to proceed.

I don't have the bandwidth to drive those changes, but I suggest we leave the issue open as an invitation for that contribution if anyone would like to make it.

handrews commented 4 months ago

@lornajane I've added it to the 3.2 milestone to indicate that we'd like to do it. We can always punt it out of that milestone if it does not fit or no one volunteers to do it.

handrews commented 2 days ago

While investigating the background for PR #4126 , I noticed this again.

Taking a look at the OAS 2.0 XML Object provides strong evidence that there is not actually a gap here, and that the name of the root element was intended to come from the schema name in the Components Object, as I previously speculated.

The key to understanding this is the word "model", which appears in a few places, starting with the first line of the XML Object section:

A metadata object that allows for more fine-tuned XML model definitions.

and then in the XML Attribute, Prefix and Namespace subsection of XML Object Examples:

In this example, a full model definition is shown.

The "full model definition" (in YAML) looks like:

Person:
  type: object
  properties:
    id:
      type: integer
      format: int32
      xml:
        attribute: true
    name:
      type: string
      xml:
        namespace: https://example.com/schema/sample
        prefix: sample

corresponding to:

<Person id="123">
    <sample:name xmlns:sample="https://example.com/schema/sample">example</sample:name>
</Person>

Everything I've quoted above appears in 2.0, 3.0, and 3.1, with the only variation being that 2.0 used swagger.io instead of example.com, and 3.1 uses https instead of http in the earlier versions.


So what's going on here?

OAS 2.0 used the term "model" very specifically, which is illustrated by the explanation of discriminator:

The value of the chosen property has to be the friendly name given to the model under the definitions property. As such, inline schema definitions, which do not have a given id, cannot be used in polymorphism.

The Definitions Object, the precursor of the schemas field of the 3.x Components Object, is introduced as:

An object to hold data types that can be consumed and produced by operations. These data types can be primitives, arrays or models.

This tells us that "models" specifically refers to type: object schemas. And if one looks at the example section headings under the Schema Object in 2.0, 3.0, and 3.1, the term "Model" is used in all object schema example titles, while the first example (a type: string schema) is titled "Primitive Sample".


This means that in 2.0 it is explicitly clear from the example and the use of the term "model" that the root element name is taken from the "model name", meaning the name under the definitions field.

This is clearly still the intent in 3.x, but the text was not updated to replace the word "model" with "schema component" or similar.

There is no need for a new field in the XML Object for this. The only change that needs to be made is to update the text to match 3.x terminology, which was no doubt missed as the XML Object section hasn't really changed since 2.0 (except for the easy search-and-replace swagger.io and http: changes).

lornajane commented 2 days ago

We can pick this up and improve the wording around the root element by describing the structure as being a component schema rather than a model definition.