stoplightio / spectral

A flexible JSON/YAML linter for creating automated style guides, with baked in support for OpenAPI v3.1, v3.0, and v2.0 as well as AsyncAPI v2.x.
https://stoplight.io/spectral
Apache License 2.0
2.45k stars 235 forks source link

Nullable allOf construct doesn't work #1603

Open philipbjorge opened 3 years ago

philipbjorge commented 3 years ago

Describe the bug I'm trying to describe a nullable ref and spectral is yelling at my examples being invalid

To Reproduce

Given this OpenAPI document:

openapi: 3.0.0
info:
  title: repro
  version: '1.0'
servers:
  - url: 'http://localhost:3000'
paths:
  '/users/{userId}':
    parameters:
      - schema:
          type: integer
        name: userId
        in: path
        required: true
        description: Id of an existing user.
    get:
      summary: Get User Info by User ID
      tags: []
      responses:
        '200':
          description: User Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
              examples:
                Get User Alice Smith:
                  value:
                    nullable_ref: null
        '404':
          description: User Not Found
      operationId: get-users-userId
      description: Retrieve the information of the user with the matching user ID.
components:
  schemas:
    Foo:
      type: object
      properties:
        bar:
          type: string
      required:
        - bar
    User:
      title: User
      type: object
      description: ''
      properties:
        nullable_ref:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/Foo"
      required:
        - nullable_ref

Run this command:

npx @stoplight/spectral lint -q repro.yaml

Received:

29:35    error  oas3-valid-oas-content-example  `nullable_ref` property type should be object                            paths./users/{userId}.get.responses[200].content.application/json.examples['Get User Alice Smith'].value.nullable_ref

In the 6.0.0 alpha, I get an error:

Error: schema is invalid: data/properties/nullable_ref/type must be equal to one of the allowed values, data/properties/nullable_ref/type/0 must be equal to one of the allowed values, data/properties/nullable_ref/type must match a schema in anyOf
    at Ajv.validateSchema (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/node_modules/ajv/dist/core.js:251:23)
    at Ajv._addSchema (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/node_modules/ajv/dist/core.js:443:18)
    at Ajv.compile (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/node_modules/ajv/dist/core.js:145:26)
    at Object.exports.schema (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/dist/functions/schema/schema.js:37:33)
    at Object.o (eval at exports.evaluateExport (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/dist/ruleset/utils/evaluators.js:89:80), <anonymous>:1:1817)
    at Object.oasExample (eval at exports.evaluateExport (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/dist/ruleset/utils/evaluators.js:89:80), <anonymous>:1:3524)
    at Object.exports.lintNode (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/dist/runner/lintNode.js:29:33)
    at callback (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/dist/runner/runner.js:38:32)
    at JSONPath._handleCallback (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/node_modules/jsonpath-plus/dist/index-node-cjs.js:306:5)
    at JSONPath._trace (/Users/philipbjorge/.npm/_npx/97956/lib/node_modules/@stoplight/spectral/node_modules/jsonpath-plus/dist/index-node-cjs.js:337:10)

Expected behavior I expected this example to pass validation -- I thought the nullable: true, allOf approach was the appropriate way to create a nullable reference in OAS 3

Screenshots If applicable, add screenshots to help explain your problem.

Environment (remove any that are not applicable):

nulltoken commented 3 years ago

@philipbjorge Not a Json schema expert, however, I believe this cannot work because allOf expects all subschemas to be be valid. IOW, nullable_ref should first be an object before even being nullable.

I believe something like this should work.

    User:
      type: object
      properties:
        nullable_ref:
          oneOf:
            - $ref: "#/components/schemas/Foo"
            - type: null
      required:
        - nullable_ref
meme commented 3 years ago

Same issue:

      type: object
      required:
        - result
      properties:
        result:
          oneOf:
            - $ref: "#/components/schemas/Foo"
            - type: "null"
 95:21  error  oas3-schema  `type` property should be equal to one of the allowed values: `array`, `boolean`, `integer`, `number`, `object`, `string`. Did you mean `number`?.  components.schemas.Response.properties.result.oneOf[3].type
philipbjorge commented 3 years ago

@meme -- Not that it helps the primary issue, but I can share that the - type: "null" construct will only be valid with a OAS 3.1 doc

phoenixy1 commented 3 years ago

We have this issue too. Comoforting to know at least that it's only an issue with spectral and that the OpenAPI file is apparently correct.

liamnichols commented 2 years ago

I think that I traced this back to an issue with ajv's nullable support:

checkin247 commented 2 years ago

updating to openapi 3.1.0 (from 3.0.0) fixed the issue for me. Thanks to : https://github.com/stoplightio/spectral/issues/1603#issuecomment-840048026

The OpenApi 3.0.0 states: "Note that there is no null type; instead, the nullable attribute is used as a modifier of the base type." Reference