spectral icon indicating copy to clipboard operation
spectral copied to clipboard

Add "Objects with properties must have type: object" rule to builtin spectral:oas ruleset

Open hjoukl opened this issue 2 years ago • 0 comments

I still think this is a sensible (opinionated, admittedly) addition to the spectral:oas ruleset. IMHO if you define properties in an OAS schema ("struct" data) you probably never want to accept data as valid that doesn't even have these properties/attributes.

(I confusingly added that to #2136 so that kind of got mixed up with this separate JSON schema related issue, sorry)

Here goes, again:

As suggested by @P0lip on #2139 I propose to add to such a built-in ruleset:

---
extends: "spectral:oas"
rules:
  properties-type-object:
    description: "Objects with properties must have type: object."
    given: "$..[?(@ && @.properties)]"
    severity: error
    # must not be resolved because $ref-defined objects shall have its type
    # defined in the referenced schema, not the referencing field (and $ref 
    # must be the only property, anyway)
    resolved: false
    # type field must be defined and contain the value object
    then:
      - field: "type"
        function: defined
      - field: "type"
        function: enumeration
        functionOptions:
          values:
            - object

Reasoning: The way OpenAPI/JSON Schema validation works wrt to structures with properties but no type: object is probably not what most users would expect (I certainly didn't):

Because IIUC a schema like

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "number": { "type": "number" },
    "street_name": { "type": "string" }
  },
  "required": ["number"],
}

is not a "de facto" restriction on a JSON object i.e. the key-value mapping aka dictionary to carry the given properties. According to JSON Schema Cort: Assertions and Instance Primitive Types only those assertions are used for validating a value which belong to the "Validation Keywords" of the data type.

Which means that all of these are valid against the above schema:

Valid:

{
  "number": 10
}

Valid:

""

Valid:

false

(basically, anything - just by accidentally omitting type: object for a "struct")

I gather the user will usually expect "struct" data to be only treated as valid if (required) properties are present in the instance object data model. The proposed rule thus omits an error for OpenAPI object schemas that define properties but not type: object.

Best, Holger

Originally posted by @hjoukl in https://github.com/stoplightio/spectral/issues/2136#issuecomment-1114544997

hjoukl avatar Jul 07 '22 09:07 hjoukl